quagga-0.99.22.4/0000755000175000017500000000000012211704577010313 500000000000000quagga-0.99.22.4/AUTHORS0000644000175000017500000000032612000052240011257 00000000000000Kunihiro Ishiguro Toshiaki Takada Yasuhiro Ohara Alex D. Zinin Gleb Natapov Akihiro Mizutani quagga-0.99.22.4/COPYING0000644000175000017500000004307612000052240011253 00000000000000 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-0.99.22.4/COPYING.LIB0000644000175000017500000006130312000052240011651 00000000000000 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-0.99.22.4/ChangeLog0000644000175000017500000000020512000052240011755 00000000000000ChangeLog information for Quagga is now recorded in our source-code management system. Please see: http://www.quagga.net/devel.php quagga-0.99.22.4/INSTALL0000644000175000017500000003660512070614057011272 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2012 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 commands `./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-0.99.22.4/INSTALL.quagga.txt0000644000175000017500000001010512211704467013341 00000000000000-------------------------------------------------------------------------- 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. (Note that considering it a bug is not a guarantee of support, merely "we agree that it is broken".) Dragonfly ? FreeBSD 4.x [In 2007, this is getting tenous.] FreeBSD 5.x FreeBSD 6.x FreeBSD-current Linux [kernel/distribution information needed] NetBSD 2.x [Note texinfo 4.6 in base system] NetBSD 3.x NetBSD 4.x NetBSD-current OpenBSD ? [info needed on what should work] Solaris 9 Solaris 10 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 CVS checkouts: In order to build from CVS, 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. 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) Becuase 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 stable distributions. The notes below explain what versions are present in various environments. NetBSD 1.6 and 2 provide texinfo 4.6. This is now considered old. NetBSD 3 and 4 provide texinfo 4.7. 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-0.99.22.4/Makefile.am0000644000175000017500000000141112200151341012243 00000000000000## Process this file with automake to produce Makefile.in. SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \ @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ @BUILD_TESTS@ DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ tools/mrlg.cgi tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ tools/zebra.el tools/multiple-bgpd.sh \ fpm/fpm.h if HAVE_LATEX HACKING.pdf: HACKING.tex $(LATEXMK) -pdf $< clean-local: -$(LATEXMK) -C HACKING.tex endif ACLOCAL_AMFLAGS = -I m4 quagga-0.99.22.4/Makefile.in0000644000175000017500000006312712211704501012274 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 = . DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(top_srcdir)/configure AUTHORS COPYING COPYING.LIB ChangeLog \ INSTALL NEWS TODO compile config.guess config.sub depcomp \ install-sh ltmain.sh missing 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) 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 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-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 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=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ cscope distdir dist dist-all distcheck ETAGS = etags CTAGS = ctags CSCOPE = cscope 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@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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 @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \ @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ @BUILD_TESTS@ DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS INSTALL.quagga.txt \ update-autotools \ vtysh/Makefile.in vtysh/Makefile.am \ tools/mrlg.cgi tools/rrcheck.pl tools/rrlookup.pl tools/zc.pl \ tools/zebra.el tools/multiple-bgpd.sh \ fpm/fpm.h 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 .PRECIOUS: 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 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(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. $(RECURSIVE_TARGETS) $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done cscopelist-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) cscopelist); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) 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; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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-recursive cscopelist cscopelist: cscopelist-recursive $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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) | GZIP=$(GZIP_ENV) gzip -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 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -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*) \ GZIP=$(GZIP_ENV) gzip -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*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(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 \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(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_LATEX_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: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ cscopelist-recursive ctags-recursive install-am install-strip \ tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-cscope \ clean-generic clean-libtool clean-local cscope cscopelist \ cscopelist-recursive ctags ctags-recursive 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-recursive uninstall uninstall-am @HAVE_LATEX_TRUE@HACKING.pdf: HACKING.tex @HAVE_LATEX_TRUE@ $(LATEXMK) -pdf $< @HAVE_LATEX_TRUE@clean-local: @HAVE_LATEX_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-0.99.22.4/NEWS0000644000175000017500000021175612211704467010744 00000000000000Note: this file lists major user-visible changes only. * Changes in Quagga 0.99.22.4 - [ospfd] Protect other implementations from malformed LSAs; see http://www.kb.cert.org/vuls/id/229804 for details. - [bgpd, zebra]: improve NEXTHOP_IPV4_IFINDEX support (non-security bugfix) * Changes in Quagga 0.99.22.3 - [ospfd] This release fixes a security issue in OSPF-API. * Changes in Quagga 0.99.22.2 - This release never existed. * Changes in Quagga 0.99.22.1 - This release has several non-security bugfixes. * 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-0.99.22.4/README0000644000175000017500000000061612000052240011071 00000000000000Quagga is free software that manages various IPv4 and IPv6 routing protocols. Currently Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng as well as very early support for IS-IS. 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-0.99.22.4/REPORTING-BUGS0000644000175000017500000000336512045513244012266 00000000000000This 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-0.99.22.4/SERVICES0000644000175000017500000000064712177450262011410 00000000000000# 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 quagga-0.99.22.4/TODO0000644000175000017500000000441512211704467010725 00000000000000 Quagga TODO list 2004/11/24 zebra: o Pointopoint address configuration. o Multiple (alias) address configuration for the interface when kernel support it [just starting]. o improve rtnetlink to handle sequence number tracking and reconciliation and resyncs. o Add support for valid and preferred lifetimes to IPv6 addresses o proper support for (at least) 1-level recursive routes o Ability to set src on routes, where systems support it. o Ability to apply route-maps to daemon route updates. bgpd: o BGP TCP MD5 authentication by password command. o HUP signal support (reload configuration file). o BGP multi-path extension o move FSM state to be per-connection, not per-peer. o Add support for internal and minimum-metric MED setting ripd: o Multipath support. ospfd: o Rewrite the incremental RT update code. o Demand circuits. o Multiple instances. o OSPF MIB [SNMP get is amost finished]. o HUP signal treatment. o Fragment Oversized LSAs o move SPF to common code o NSSA priority rules (RFC3101 2.4) o Type-7 address ranges (RFC3101 2.2) o Originating Type-7 default into area (RFC3101 2.7) ospf6d: o move SPF to common code o add router-id lookups isisd: o finish SPF o select nearest L2 when running SPF for L1 o remove the routes when holding time for nexthop expires o redistribution o autosummary o Mesh groups (RFC2973) o Crypto authentication (RFC3567) lib: o improve route_table speed, eg strided lookups for common prefix depths. o improve hash tables, eg auto-growing hash tables o move performance sensitive users of hashes over to jhash o clean up linked lists o ipv6 addresses need concept of valid/preferred o implement a generic daemon access/control protocol (eg D-Bus like? simplified SNMP-a-like?) o merge SPF code from ospfd and ospf6d into a common libspf o depends-on(generic A/C protocol) move snmp to seperate daemon o extend command definitions to allow them to be self-documenting o i18n command help strings o Document the exported API (DocBook/Doxygen?) vtysh: o untangle readline specific bits o add a vtyd with a vty (ie telnet) frontend (as opposed to readline) o depends-on(generic A/C protocol) use such o better AAA support than just PAM, eg krb5, SASL, LDAP.. ----------------------------- quagga-0.99.22.4/aclocal.m40000644000175000017500000010656412211704477012106 00000000000000# generated automatically by aclocal 1.12.6 -*- Autoconf -*- # Copyright (C) 1996-2012 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_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'.])]) # Copyright (C) 2002-2012 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.12' 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.12.6], [], [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.12.6])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-2012 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], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2012 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-2012 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-2012 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], [{ # Autoconf 2.62 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-2012 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. # 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.62])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. For more info, see: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_INIT_AUTOMAKE-invocation]) 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. 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 dnl Support for Objective C++ was only introduced in Autoconf 2.65, dnl but we still cater to Autoconf 2.62. m4_ifdef([AC_PROG_OBJCXX], [AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The 'parallel-tests' driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl 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 ]) 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-2012 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}" != 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-2012 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-2012 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 ]) # Copyright (C) 1999-2012 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. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != 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 dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2012 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 supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl 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 --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2012 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])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2012 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) 2001-2012 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-2012 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-2012 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}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of '-'. 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-0.99.22.4/babeld/0000755000175000017500000000000012211704577011524 500000000000000quagga-0.99.22.4/babeld/Makefile.am0000644000175000017500000000150512177450262013501 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbabel.a sbin_PROGRAMS = babeld libbabel_a_SOURCES = \ babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ route.c xroute.c message.c resend.c babel_interface.c babeld.c \ babel_filter.c noinst_HEADERS = \ babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ route.h xroute.h message.h resend.h babel_interface.h babeld.h \ babel_filter.h babel_main.h babeld_SOURCES = \ babel_main.c $(libbabel_a_SOURCES) babeld_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = babeld.conf.sample quagga-0.99.22.4/babeld/Makefile.in0000644000175000017500000005574012211704501013507 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 = babeld$(EXEEXT) subdir = babeld DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru libbabel_a_AR = $(AR) $(ARFLAGS) libbabel_a_LIBADD = am_libbabel_a_OBJECTS = babel_zebra.$(OBJEXT) net.$(OBJEXT) \ kernel.$(OBJEXT) util.$(OBJEXT) source.$(OBJEXT) \ neighbour.$(OBJEXT) route.$(OBJEXT) xroute.$(OBJEXT) \ message.$(OBJEXT) resend.$(OBJEXT) babel_interface.$(OBJEXT) \ babeld.$(OBJEXT) babel_filter.$(OBJEXT) libbabel_a_OBJECTS = $(am_libbabel_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = babel_zebra.$(OBJEXT) net.$(OBJEXT) kernel.$(OBJEXT) \ util.$(OBJEXT) source.$(OBJEXT) neighbour.$(OBJEXT) \ route.$(OBJEXT) xroute.$(OBJEXT) message.$(OBJEXT) \ resend.$(OBJEXT) babel_interface.$(OBJEXT) babeld.$(OBJEXT) \ babel_filter.$(OBJEXT) am_babeld_OBJECTS = babel_main.$(OBJEXT) $(am__objects_1) babeld_OBJECTS = $(am_babeld_OBJECTS) babeld_DEPENDENCIES = ../lib/libzebra.la 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libbabel_a_SOURCES) $(babeld_SOURCES) DIST_SOURCES = $(libbabel_a_SOURCES) $(babeld_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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbabel.a libbabel_a_SOURCES = \ babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ route.c xroute.c message.c resend.c babel_interface.c babeld.c \ babel_filter.c noinst_HEADERS = \ babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ route.h xroute.h message.h resend.h babel_interface.h babeld.h \ babel_filter.h babel_main.h babeld_SOURCES = \ babel_main.c $(libbabel_a_SOURCES) babeld_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = babeld.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 babeld/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu babeld/Makefile .PRECIOUS: 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) libbabel.a: $(libbabel_a_OBJECTS) $(libbabel_a_DEPENDENCIES) $(EXTRA_libbabel_a_DEPENDENCIES) -rm -f libbabel.a $(libbabel_a_AR) libbabel.a $(libbabel_a_OBJECTS) $(libbabel_a_LIBADD) $(RANLIB) libbabel.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 babeld$(EXEEXT): $(babeld_OBJECTS) $(babeld_DEPENDENCIES) $(EXTRA_babeld_DEPENDENCIES) @rm -f babeld$(EXEEXT) $(LINK) $(babeld_OBJECTS) $(babeld_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babeld.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/neighbour.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xroute.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/babeld/babel_filter.c0000644000175000017500000001136612177450262014231 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include "babel_filter.h" #include "vty.h" #include "filter.h" #include "log.h" #include "plist.h" #include "distribute.h" #include "util.h" int babel_filter(int output, const unsigned char *prefix, unsigned short plen, unsigned int ifindex) { struct interface *ifp = if_lookup_by_index(ifindex); babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL; struct prefix p; struct distribute *dist; struct access_list *alist; struct prefix_list *plist; int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN; int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) uchar_to_inaddr(&p.u.prefix4, prefix); else uchar_to_in6addr(&p.u.prefix6, prefix); if (babel_ifp != NULL && babel_ifp->list[filter]) { if (access_list_apply (babel_ifp->list[filter], &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } if (babel_ifp != NULL && babel_ifp->prefix[filter]) { if (prefix_list_apply (babel_ifp->prefix[filter], &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } /* 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, &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } } if (dist->prefix[distribute]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); if (plist) { if (prefix_list_apply (plist, &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } } } return 0; } quagga-0.99.22.4/babeld/babel_filter.h0000644000175000017500000000415612177450262014235 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #ifndef BABELD_BABEL_FILTER_H #define BABELD_BABEL_FILTER_H #include #include "prefix.h" #include "babel_interface.h" int babel_filter(int output, const unsigned char *prefix, unsigned short plen, unsigned int index); #endif /* BABELD_BABEL_FILTER_H */ quagga-0.99.22.4/babeld/babel_interface.c0000644000175000017500000007165412177450262014712 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include #include "memory.h" #include "log.h" #include "command.h" #include "prefix.h" #include "vector.h" #include "distribute.h" #include "babel_main.h" #include "util.h" #include "kernel.h" #include "babel_interface.h" #include "message.h" #include "route.h" #include "babel_zebra.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0) static int babel_enable_if_lookup (const char *ifname); static int babel_enable_if_add (const char *ifname); static int babel_enable_if_delete (const char *ifname); static int interface_recalculate(struct interface *ifp); static int interface_reset(struct interface *ifp); static int babel_if_new_hook (struct interface *ifp); static int babel_if_delete_hook (struct interface *ifp); static int interface_config_write (struct vty *vty); static babel_interface_nfo * babel_interface_allocate (void); static void babel_interface_free (babel_interface_nfo *bi); static vector babel_enable_if; /* enable interfaces (by cmd). */ static struct cmd_node babel_interface_node = /* babeld's interface node. */ { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; int babel_interface_up (int cmd, struct zclient *client, zebra_size_t length) { struct stream *s = NULL; struct interface *ifp = NULL; debugf(BABEL_DEBUG_IF, "receive a 'interface up'"); s = zclient->ibuf; ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) { return 0; } interface_recalculate(ifp); return 0; } int babel_interface_down (int cmd, struct zclient *client, zebra_size_t length) { struct stream *s = NULL; struct interface *ifp = NULL; debugf(BABEL_DEBUG_IF, "receive a 'interface down'"); s = zclient->ibuf; ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) { return 0; } interface_reset(ifp); return 0; } int babel_interface_add (int cmd, struct zclient *client, zebra_size_t length) { struct interface *ifp = NULL; debugf(BABEL_DEBUG_IF, "receive a 'interface add'"); /* read and add the interface in the iflist. */ ifp = zebra_interface_add_read (zclient->ibuf); if (ifp == NULL) { return 0; } interface_recalculate(ifp); return 0; } int babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length) { struct interface *ifp; struct stream *s; debugf(BABEL_DEBUG_IF, "receive a 'interface delete'"); s = zclient->ibuf; ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) return 0; if (IS_ENABLE(ifp)) interface_reset(ifp); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ ifp->ifindex = IFINDEX_INTERNAL; return 0; } int babel_interface_address_add (int cmd, struct zclient *client, zebra_size_t length) { babel_interface_nfo *babel_ifp; struct connected *ifc; struct prefix *prefix; debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (ifc == NULL) return 0; prefix = ifc->address; if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); if (babel_ifp->ipv4 == NULL) { babel_ifp->ipv4 = malloc(4); if (babel_ifp->ipv4 == NULL) { zlog_err("not einough memory"); } else { memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4); } } } send_request(ifc->ifp, NULL, 0); send_update(ifc->ifp, 0, NULL, 0); return 0; } int babel_interface_address_delete (int cmd, struct zclient *client, zebra_size_t length) { babel_interface_nfo *babel_ifp; struct connected *ifc; struct prefix *prefix; debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (ifc == NULL) return 0; prefix = ifc->address; if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); if (babel_ifp->ipv4 != NULL && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) { free(babel_ifp->ipv4); babel_ifp->ipv4 = NULL; } } send_request(ifc->ifp, NULL, 0); send_update(ifc->ifp, 0, NULL, 0); return 0; } /* Lookup function. */ static int babel_enable_if_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (babel_enable_if); i++) if ((str = vector_slot (babel_enable_if, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } /* Add interface to babel_enable_if. */ static int babel_enable_if_add (const char *ifname) { int ret; struct interface *ifp = NULL; ret = babel_enable_if_lookup (ifname); if (ret >= 0) return -1; vector_set (babel_enable_if, strdup (ifname)); ifp = if_lookup_by_name(ifname); if (ifp != NULL) interface_recalculate(ifp); return 1; } /* Delete interface from babel_enable_if. */ static int babel_enable_if_delete (const char *ifname) { int babel_enable_if_index; char *str; struct interface *ifp = NULL; babel_enable_if_index = babel_enable_if_lookup (ifname); if (babel_enable_if_index < 0) return -1; str = vector_slot (babel_enable_if, babel_enable_if_index); free (str); vector_unset (babel_enable_if, babel_enable_if_index); ifp = if_lookup_by_name(ifname); if (ifp != NULL) interface_reset(ifp); return 1; } /* [Babel Command] Babel enable on specified interface or matched network. */ DEFUN (babel_network, babel_network_cmd, "network IF_OR_ADDR", "Enable Babel protocol on specified interface or network.\n" "Interface or address") { int ret; struct prefix p; ret = str2prefix (argv[0], &p); /* Given string is: */ if (ret) /* an IPv4 or v6 network */ return CMD_ERR_NO_MATCH; /* not implemented yet */ else /* an interface name */ ret = babel_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; } /* [Babel Command] Babel enable on specified interface or matched network. */ DEFUN (no_babel_network, no_babel_network_cmd, "no network IF_OR_ADDR", NO_STR "Disable Babel protocol on specified interface or network.\n" "Interface or address") { int ret; struct prefix p; ret = str2prefix (argv[0], &p); /* Given string is: */ if (ret) /* an IPv4 or v6 network */ return CMD_ERR_NO_MATCH; /* not implemented yet */ else /* an interface name */ ret = babel_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; } /* There are a number of interface parameters that must be changed when an interface becomes wired/wireless. In Quagga, they cannot be configured separately. */ static void babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired) { if(wired) { babel_ifp->flags |= BABEL_IF_WIRED; babel_ifp->cost = 96; babel_ifp->flags &= ~BABEL_IF_LQ; } else { babel_ifp->flags &= ~BABEL_IF_WIRED; babel_ifp->cost = 256; babel_ifp->flags |= BABEL_IF_LQ; } } /* [Interface Command] Tell the interface is wire. */ DEFUN (babel_set_wired, babel_set_wired_cmd, "babel wired", "Babel interface commands\n" "Enable wired optimisations") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_set_wired_internal(babel_ifp, 1); return CMD_SUCCESS; } /* [Interface Command] Tell the interface is wireless (default). */ DEFUN (babel_set_wireless, babel_set_wireless_cmd, "babel wireless", "Babel interface commands\n" "Disable wired optimiations (assume wireless)") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_set_wired_internal(babel_ifp, 0); return CMD_SUCCESS; } /* [Interface Command] Enable split horizon. */ DEFUN (babel_split_horizon, babel_split_horizon_cmd, "babel split-horizon", "Babel interface commands\n" "Enable split horizon processing") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON; return CMD_SUCCESS; } /* [Interface Command] Disable split horizon (default). */ DEFUN (no_babel_split_horizon, no_babel_split_horizon_cmd, "no babel split-horizon", NO_STR "Babel interface commands\n" "Disable split horizon processing") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON; return CMD_SUCCESS; } /* [Interface Command]. */ DEFUN (babel_set_hello_interval, babel_set_hello_interval_cmd, "babel hello-interval <20-655340>", "Babel interface commands\n" "Time between scheduled hellos\n" "Milliseconds\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; int interval; VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->hello_interval = interval; return CMD_SUCCESS; } /* [Interface Command]. */ DEFUN (babel_set_update_interval, babel_set_update_interval_cmd, "babel update-interval <20-655340>", "Babel interface commands\n" "Time between scheduled updates\n" "Milliseconds\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; int interval; VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->update_interval = interval; return CMD_SUCCESS; } /* This should be no more than half the hello interval, so that hellos aren't sent late. The result is in milliseconds. */ unsigned jitter(babel_interface_nfo *babel_ifp, int urgent) { unsigned interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else interval = MIN(interval, 4000); return roughly(interval) / 4; } unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent) { unsigned interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else interval = MIN(interval, 4000); return roughly(interval); } /* calculate babeld's specific datas of an interface (change when the interface change) */ static int interface_recalculate(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned char *tmp = NULL; int mtu, rc; struct ipv6_mreq mreq; if (!IS_ENABLE(ifp)) return -1; if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) { interface_reset(ifp); return -1; } babel_ifp->flags |= BABEL_IF_IS_UP; mtu = MIN(ifp->mtu, ifp->mtu6); /* We need to be able to fit at least two messages into a packet, so MTUs below 116 require lower layer fragmentation. */ /* In IPv6, the minimum MTU is 1280, and every host must be able to reassemble up to 1500 bytes, but I'd rather not rely on this. */ if(mtu < 128) { debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).", mtu, ifp->name, ifp->ifindex); mtu = 128; } /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ babel_ifp->bufsize = mtu - sizeof(packet_header) - 60; tmp = babel_ifp->sendbuf; babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize); if(babel_ifp->sendbuf == NULL) { zlog_err("Couldn't reallocate sendbuf."); free(tmp); babel_ifp->bufsize = 0; return -1; } tmp = NULL; resize_receive_buffer(mtu); memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) { zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s", ifp->name, safe_strerror(errno)); /* This is probably due to a missing link-local address, so down this interface, and wait until the main loop tries to up it again. */ interface_reset(ifp); return -1; } set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); send_hello(ifp); send_request(ifp, NULL, 0); update_interface_metric(ifp); debugf(BABEL_DEBUG_COMMON, "Upped interface %s (%s, cost=%d, channel=%d%s).", ifp->name, (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", babel_ifp->cost, babel_ifp->channel, babel_ifp->ipv4 ? ", IPv4" : ""); if(rc > 0) send_update(ifp, 0, NULL, 0); return 1; } /* Reset the interface as it was new: it's not removed from the interface list, and may be considered as a upped interface. */ static int interface_reset(struct interface *ifp) { int rc; struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if (!(babel_ifp->flags & BABEL_IF_IS_UP)) return 0; debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name); babel_ifp->flags &= ~BABEL_IF_IS_UP; flush_interface_routes(ifp, 0); babel_ifp->buffered = 0; babel_ifp->bufsize = 0; free(babel_ifp->sendbuf); babel_ifp->num_buffered_updates = 0; babel_ifp->update_bufsize = 0; if(babel_ifp->buffered_updates) free(babel_ifp->buffered_updates); babel_ifp->buffered_updates = NULL; babel_ifp->sendbuf = NULL; if(ifp->ifindex > 0) { memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s", ifp->name, safe_strerror(errno)); } update_interface_metric(ifp); debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).", ifp->name, (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", babel_ifp->cost, babel_ifp->ipv4 ? ", IPv4" : ""); return 1; } /* Send retraction to all, and reset all interfaces statistics. */ void babel_interface_close_all(void) { struct interface *ifp = NULL; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; send_wildcard_retraction(ifp); /* Make sure that we expire quickly from our neighbours' association caches. */ send_hello_noupdate(ifp, 10); flushbuf(ifp); usleep(roughly(1000)); gettime(&babel_now); } FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; /* Make sure they got it. */ send_wildcard_retraction(ifp); send_hello_noupdate(ifp, 1); flushbuf(ifp); usleep(roughly(10000)); gettime(&babel_now); interface_reset(ifp); } } /* return "true" if address is one of our ipv6 addresses */ int is_interface_ll_address(struct interface *ifp, const unsigned char *address) { struct connected *connected; struct listnode *node; if(!if_up(ifp)) return 0; FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) { if(connected->address->family == AF_INET6 && memcmp(&connected->address->u.prefix6, address, 16) == 0) return 1; } return 0; } static void show_babel_interface_sub (struct vty *vty, struct interface *ifp) { int is_up; babel_interface_nfo *babel_ifp; 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 %s%s", ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE); if (babel_enable_if_lookup (ifp->name) < 0) { vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE); return; } if (!is_up) { vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE); return; } babel_ifp = babel_get_if_nfo (ifp); vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE); vty_out (vty, " Operating mode is \"%s\"%s", CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE); vty_out (vty, " Split horizon mode is %s%s", CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE); vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE); vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE); } DEFUN (show_babel_interface, show_babel_interface_cmd, "show babel interface [INTERFACE]", SHOW_STR IP_STR "Babel information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; struct listnode *node; if (argc == 0) { for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) show_babel_interface_sub (vty, ifp); return CMD_SUCCESS; } if ((ifp = if_lookup_by_name (argv[0])) == NULL) { vty_out (vty, "No such interface name%s", VTY_NEWLINE); return CMD_WARNING; } show_babel_interface_sub (vty, ifp); return CMD_SUCCESS; } static void show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh) { vty_out (vty, "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s", format_address(neigh->address), neigh->ifp->name, neigh->reach, neighbour_rxcost(neigh), neigh->txcost, if_up(neigh->ifp) ? "" : " (down)", VTY_NEWLINE); } DEFUN (show_babel_neighbour, show_babel_neighbour_cmd, "show babel neighbour [INTERFACE]", SHOW_STR IP_STR "Babel information\n" "Print neighbours\n" "Interface name\n") { struct neighbour *neigh; struct interface *ifp; if (argc == 0) { FOR_ALL_NEIGHBOURS(neigh) { show_babel_neighbour_sub(vty, neigh); } return CMD_SUCCESS; } if ((ifp = if_lookup_by_name (argv[0])) == NULL) { vty_out (vty, "No such interface name%s", VTY_NEWLINE); return CMD_WARNING; } FOR_ALL_NEIGHBOURS(neigh) { if(ifp->ifindex == neigh->ifp->ifindex) { show_babel_neighbour_sub(vty, neigh); } } return CMD_SUCCESS; } static void show_babel_routes_sub (struct babel_route *route, void *closure) { struct vty *vty = (struct vty*) closure; const unsigned char *nexthop = memcmp(route->nexthop, route->neigh->address, 16) == 0 ? NULL : route->nexthop; char channels[100]; if(route->channels[0] == 0) channels[0] = '\0'; else { int k, j = 0; snprintf(channels, 100, " chan ("); j = strlen(channels); for(k = 0; k < DIVERSITY_HOPS; k++) { if(route->channels[k] == 0) break; if(k > 0) channels[j++] = ','; snprintf(channels + j, 100 - j, "%d", route->channels[k]); j = strlen(channels); } snprintf(channels + j, 100 - j, ")"); if(k == 0) channels[0] = '\0'; } vty_out(vty, "%s metric %d refmetric %d id %s seqno %d%s age %d " "via %s neigh %s%s%s%s%s", format_prefix(route->src->prefix, route->src->plen), route_metric(route), route->refmetric, format_eui64(route->src->id), (int)route->seqno, channels, (int)(babel_now.tv_sec - route->time), route->neigh->ifp->name, format_address(route->neigh->address), nexthop ? " nexthop " : "", nexthop ? format_address(nexthop) : "", route->installed ? " (installed)" : route_feasible(route) ? " (feasible)" : "", VTY_NEWLINE); } static void show_babel_xroutes_sub (struct xroute *xroute, void *closure) { struct vty *vty = (struct vty *) closure; vty_out(vty, "%s metric %d (exported)%s", format_prefix(xroute->prefix, xroute->plen), xroute->metric, VTY_NEWLINE); } DEFUN (show_babel_database, show_babel_database_cmd, "show babel database", SHOW_STR IP_STR "Babel information\n" "Database information\n" "No attributes\n") { for_all_routes(show_babel_routes_sub, vty); for_all_xroutes(show_babel_xroutes_sub, vty); return CMD_SUCCESS; } DEFUN (show_babel_parameters, show_babel_parameters_cmd, "show babel parameters", SHOW_STR IP_STR "Babel information\n" "Configuration information\n" "No attributes\n") { vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE); show_babel_main_configuration(vty); vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE); config_show_distribute(vty); return CMD_SUCCESS; } void babel_if_init () { /* initialize interface list */ if_init(); if_add_hook (IF_NEW_HOOK, babel_if_new_hook); if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook); babel_enable_if = vector_init (1); /* install interface node and commands */ install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_node (&babel_interface_node, interface_config_write); install_default(INTERFACE_NODE); install_element(INTERFACE_NODE, &interface_cmd); install_element(INTERFACE_NODE, &no_interface_cmd); install_element(BABEL_NODE, &babel_network_cmd); install_element(BABEL_NODE, &no_babel_network_cmd); install_element(INTERFACE_NODE, &babel_split_horizon_cmd); install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd); install_element(INTERFACE_NODE, &babel_set_wired_cmd); install_element(INTERFACE_NODE, &babel_set_wireless_cmd); install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); install_element(INTERFACE_NODE, &babel_set_update_interval_cmd); /* "show babel ..." commands */ install_element(VIEW_NODE, &show_babel_interface_cmd); install_element(ENABLE_NODE, &show_babel_interface_cmd); install_element(VIEW_NODE, &show_babel_neighbour_cmd); install_element(ENABLE_NODE, &show_babel_neighbour_cmd); install_element(VIEW_NODE, &show_babel_database_cmd); install_element(ENABLE_NODE, &show_babel_database_cmd); install_element(VIEW_NODE, &show_babel_parameters_cmd); install_element(ENABLE_NODE, &show_babel_parameters_cmd); } /* hooks: functions called respectively when struct interface is created or deleted. */ static int babel_if_new_hook (struct interface *ifp) { ifp->info = babel_interface_allocate(); return 0; } static int babel_if_delete_hook (struct interface *ifp) { babel_interface_free(ifp->info); ifp->info = NULL; return 0; } /* Output an "interface" section for each of the known interfaces with babeld-specific statement lines where appropriate. */ static int interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; int write = 0; 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); if (IS_ENABLE (ifp)) { babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); /* wireless/no split-horizon is the default */ if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { vty_out (vty, " babel wired%s", VTY_NEWLINE); write++; } if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) { vty_out (vty, " babel split-horizon%s", VTY_NEWLINE); write++; } if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL) { vty_out (vty, " babel hello-interval %u%s", babel_ifp->hello_interval, VTY_NEWLINE); write++; } if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL) { vty_out (vty, " babel update-interval %u%s", babel_ifp->update_interval, VTY_NEWLINE); write++; } } vty_out (vty, "!%s", VTY_NEWLINE); write++; } return write; } /* Output a "network" statement line for each of the enabled interfaces. */ int babel_enable_if_config_write (struct vty * vty) { unsigned int i, lines = 0; char *str; for (i = 0; i < vector_active (babel_enable_if); i++) if ((str = vector_slot (babel_enable_if, i)) != NULL) { vty_out (vty, " network %s%s", str, VTY_NEWLINE); lines++; } return lines; } /* functions to allocate or free memory for a babel_interface_nfo, filling needed fields */ static babel_interface_nfo * babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); if(babel_ifp == NULL) return NULL; /* Here are set the default values for an interface. */ memset(babel_ifp, 0, sizeof(babel_interface_nfo)); /* All flags are unset */ babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->hello_seqno = (random() & 0xFFFF); babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL; babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL; babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; babel_set_wired_internal(babel_ifp, 0); return babel_ifp; } static void babel_interface_free (babel_interface_nfo *babel_ifp) { XFREE(MTYPE_BABEL_IF, babel_ifp); } quagga-0.99.22.4/babeld/babel_interface.h0000644000175000017500000001254212177450262014706 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #ifndef BABEL_INTERFACE_H #define BABEL_INTERFACE_H #include #include "zclient.h" #include "vty.h" #define CONFIG_DEFAULT 0 #define CONFIG_NO 1 #define CONFIG_YES 2 /* babeld interface informations */ struct babel_interface { unsigned short flags; /* see below */ unsigned short cost; int channel; struct timeval hello_timeout; struct timeval update_timeout; struct timeval flush_timeout; struct timeval update_flush_timeout; unsigned char *ipv4; int buffered; int bufsize; char have_buffered_hello; char have_buffered_id; char have_buffered_nh; char have_buffered_prefix; unsigned char buffered_id[16]; unsigned char buffered_nh[4]; unsigned char buffered_prefix[16]; unsigned char *sendbuf; struct buffered_update *buffered_updates; int num_buffered_updates; int update_bufsize; time_t bucket_time; unsigned int bucket; time_t last_update_time; unsigned short hello_seqno; unsigned hello_interval; unsigned update_interval; /* For filter type slot. */ #define BABEL_FILTER_IN 0 #define BABEL_FILTER_OUT 1 #define BABEL_FILTER_MAX 2 struct access_list *list[BABEL_FILTER_MAX]; /* Access-list. */ struct prefix_list *prefix[BABEL_FILTER_MAX]; /* Prefix-list. */ }; typedef struct babel_interface babel_interface_nfo; static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) { return ((babel_interface_nfo*) ifp->info); } /* babel_interface_nfo flags */ #define BABEL_IF_IS_UP (1 << 0) #define BABEL_IF_WIRED (1 << 1) #define BABEL_IF_SPLIT_HORIZON (1 << 2) #define BABEL_IF_LQ (1 << 3) #define BABEL_IF_FARAWAY (1 << 4) /* Only INTERFERING can appear on the wire. */ #define BABEL_IF_CHANNEL_UNKNOWN 0 #define BABEL_IF_CHANNEL_INTERFERING 255 #define BABEL_IF_CHANNEL_NONINTERFERING -2 static inline int if_up(struct interface *ifp) { return (if_is_operative(ifp) && ifp->connected != NULL && (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP)); } /* types: struct interface _ifp, struct listnode node */ #define FOR_ALL_INTERFACES(_ifp, _node) \ for(ALL_LIST_ELEMENTS_RO(iflist, _node, _ifp)) /* types: struct interface *ifp, struct connected *_connected, struct listnode *node */ #define FOR_ALL_INTERFACES_ADDRESSES(ifp, _connected, _node) \ for(ALL_LIST_ELEMENTS_RO(ifp->connected, _node, _connected)) struct buffered_update { unsigned char id[8]; unsigned char prefix[16]; unsigned char plen; unsigned char pad[3]; }; /* init function */ void babel_if_init(void); /* Callback functions for zebra client */ int babel_interface_up (int, struct zclient *, zebra_size_t); int babel_interface_down (int, struct zclient *, zebra_size_t); int babel_interface_add (int, struct zclient *, zebra_size_t); int babel_interface_delete (int, struct zclient *, zebra_size_t); int babel_interface_address_add (int, struct zclient *, zebra_size_t); int babel_interface_address_delete (int, struct zclient *, zebra_size_t); unsigned jitter(babel_interface_nfo *, int); unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); /* return "true" if "address" is one of our ipv6 addresses */ int is_interface_ll_address(struct interface *ifp, const unsigned char *address); /* Send retraction to all, and reset all interfaces statistics. */ void babel_interface_close_all(void); extern int babel_enable_if_config_write (struct vty *); #endif quagga-0.99.22.4/babeld/babel_main.c0000644000175000017500000003547312177450262013675 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ /* include zebra library */ #include #include "getopt.h" #include "if.h" #include "log.h" #include "thread.h" #include "privs.h" #include "sigevent.h" #include "version.h" #include "command.h" #include "vty.h" #include "memory.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "kernel.h" #include "babel_interface.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #include "message.h" #include "resend.h" #include "babel_zebra.h" static void babel_init (int argc, char **argv); static char *babel_get_progname(char *argv_0); static void babel_fail(void); static void babel_init_random(void); static void babel_replace_by_null(int fd); static void babel_init_signals(void); static void babel_exit_properly(void); static void babel_save_state_file(void); struct thread_master *master; /* quagga's threads handler */ struct timeval babel_now; /* current time */ unsigned char myid[8]; /* unique id (mac address of an interface) */ int debug = 0; int resend_delay = -1; static const char *pidfile = PATH_BABELD_PID; const unsigned char zeroes[16] = {0}; const unsigned char ones[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static const char *state_file = DAEMON_VTY_DIR "/babel-state"; unsigned char protocol_group[16]; /* babel's link-local multicast address */ int protocol_port; /* babel's port */ int protocol_socket = -1; /* socket: communicate with others babeld */ static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; static char *babel_config_file = NULL; static char *babel_vty_addr = NULL; static int babel_vty_port = BABEL_VTY_PORT; /* Babeld 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 } }; /* babeld privileges */ static zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; static struct zebra_privs_t babeld_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 }; int main(int argc, char **argv) { struct thread thread; /* and print banner too */ babel_init(argc, argv); while (thread_fetch (master, &thread)) { thread_call (&thread); } return 0; } static void babel_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 Babel routing 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); } /* make initialisations witch don't need infos about kernel(interfaces, etc.) */ static void babel_init(int argc, char **argv) { int rc, opt; int do_daemonise = 0; char *progname = NULL; /* Set umask before anything for security */ umask (0027); progname = babel_get_progname(argv[0]); /* set default log (lib/log.h) */ zlog_default = openzlog(progname, ZLOG_BABEL, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* set log destination as stdout until the config file is read */ zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); babel_init_random(); /* set the Babel's default link-local multicast address and Babel's port */ parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); protocol_port = 6696; /* get options */ 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': babel_config_file = optarg; break; case 'i': pidfile = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'A': babel_vty_addr = optarg; break; case 'P': babel_vty_port = atoi (optarg); if (babel_vty_port <= 0 || babel_vty_port > 0xffff) babel_vty_port = BABEL_VTY_PORT; break; case 'u': babeld_privs.user = optarg; break; case 'g': babeld_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'h': babel_usage (progname, 0); break; default: babel_usage (progname, 1); break; } } /* create the threads handler */ master = thread_master_create (); /* Library inits. */ zprivs_init (&babeld_privs); babel_init_signals(); cmd_init (1); vty_init (master); memory_init (); resend_delay = BABEL_DEFAULT_RESEND_DELAY; babel_replace_by_null(STDIN_FILENO); if (do_daemonise && daemonise() < 0) { zlog_err("daemonise: %s", safe_strerror(errno)); exit (1); } /* write pid file */ if (pid_output(pidfile) < 0) { zlog_err("error while writing pidfile"); exit (1); }; /* init some quagga's dependencies, and babeld's commands */ babeld_quagga_init(); /* init zebra client's structure and it's commands */ /* this replace kernel_setup && kernel_setup_socket */ babelz_zebra_init (); /* Sort all installed commands. */ sort_node (); /* Get zebra configuration file. */ zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); vty_read_config (babel_config_file, babel_config_default); /* Create VTY socket */ vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH); /* init buffer */ rc = resize_receive_buffer(1500); if(rc < 0) babel_fail(); schedule_neighbours_check(5000, 1); zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port); } /* return the progname (without path, example: "./x/progname" --> "progname") */ static char * babel_get_progname(char *argv_0) { char *p = strrchr (argv_0, '/'); return (p ? ++p : argv_0); } static void babel_fail(void) { exit(1); } /* initialize random value, and set 'babel_now' by the way. */ static void babel_init_random(void) { gettime(&babel_now); int rc; unsigned int seed; rc = read_random_bytes(&seed, sizeof(seed)); if(rc < 0) { zlog_err("read(random): %s", safe_strerror(errno)); seed = 42; } seed ^= (babel_now.tv_sec ^ babel_now.tv_usec); srandom(seed); } /* close fd, and replace it by "/dev/null" exit if error */ static void babel_replace_by_null(int fd) { int fd_null; int rc; fd_null = open("/dev/null", O_RDONLY); if(fd_null < 0) { zlog_err("open(null): %s", safe_strerror(errno)); exit(1); } rc = dup2(fd_null, fd); if(rc < 0) { zlog_err("dup2(null, 0): %s", safe_strerror(errno)); exit(1); } close(fd_null); } /* Load the state file: check last babeld's running state, usefull in case of "/etc/init.d/babeld restart" */ void babel_load_state_file(void) { int fd; int rc; fd = open(state_file, O_RDONLY); if(fd < 0 && errno != ENOENT) zlog_err("open(babel-state: %s)", safe_strerror(errno)); rc = unlink(state_file); if(fd >= 0 && rc < 0) { zlog_err("unlink(babel-state): %s", safe_strerror(errno)); /* If we couldn't unlink it, it's probably stale. */ close(fd); fd = -1; } if(fd >= 0) { char buf[100]; char buf2[100]; int s; long t; rc = read(fd, buf, 99); if(rc < 0) { zlog_err("read(babel-state): %s", safe_strerror(errno)); } else { buf[rc] = '\0'; rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t); if(rc == 3 && s >= 0 && s <= 0xFFFF) { unsigned char sid[8]; rc = parse_eui64(buf2, sid); if(rc < 0) { zlog_err("Couldn't parse babel-state."); } else { struct timeval realnow; debugf(BABEL_DEBUG_COMMON, "Got %s %d %ld from babel-state.", format_eui64(sid), s, t); gettimeofday(&realnow, NULL); if(memcmp(sid, myid, 8) == 0) myseqno = seqno_plus(s, 1); else zlog_err("ID mismatch in babel-state. id=%s; old=%s", format_eui64(myid), format_eui64(sid)); } } else { zlog_err("Couldn't parse babel-state."); } } close(fd); fd = -1; } } static void babel_sigexit(void) { zlog_notice("Terminating on signal"); babel_exit_properly(); } static void babel_sigusr1 (void) { zlog_rotate (NULL); } static void babel_init_signals(void) { static struct quagga_signal_t babel_signals[] = { { .signal = SIGUSR1, .handler = &babel_sigusr1, }, { .signal = SIGINT, .handler = &babel_sigexit, }, { .signal = SIGTERM, .handler = &babel_sigexit, }, }; signal_init (master, array_size(babel_signals), babel_signals); } static void babel_exit_properly(void) { debugf(BABEL_DEBUG_COMMON, "Exiting..."); usleep(roughly(10000)); gettime(&babel_now); /* Uninstall and flush all routes. */ debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); flush_all_routes(); babel_interface_close_all(); babel_zebra_close_connexion(); babel_save_state_file(); debugf(BABEL_DEBUG_COMMON, "Remove pid file."); if(pidfile) unlink(pidfile); debugf(BABEL_DEBUG_COMMON, "Done."); exit(0); } static void babel_save_state_file(void) { int fd; int rc; debugf(BABEL_DEBUG_COMMON, "Save state file."); fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644); if(fd < 0) { zlog_err("creat(babel-state): %s", safe_strerror(errno)); unlink(state_file); } else { struct timeval realnow; char buf[100]; gettimeofday(&realnow, NULL); rc = snprintf(buf, 100, "%s %d %ld\n", format_eui64(myid), (int)myseqno, (long)realnow.tv_sec); if(rc < 0 || rc >= 100) { zlog_err("write(babel-state): overflow."); unlink(state_file); } else { rc = write(fd, buf, rc); if(rc < 0) { zlog_err("write(babel-state): %s", safe_strerror(errno)); unlink(state_file); } fsync(fd); } close(fd); } } void show_babel_main_configuration (struct vty *vty) { vty_out(vty, "pid file = %s%s" "state file = %s%s" "configuration file = %s%s" "protocol informations:%s" " multicast address = %s%s" " port = %d%s" "vty address = %s%s" "vty port = %d%s" "id = %s%s" "allow_duplicates = %s%s" "kernel_metric = %d%s", pidfile, VTY_NEWLINE, state_file, VTY_NEWLINE, babel_config_file ? babel_config_file : babel_config_default, VTY_NEWLINE, VTY_NEWLINE, format_address(protocol_group), VTY_NEWLINE, protocol_port, VTY_NEWLINE, babel_vty_addr ? babel_vty_addr : "None", VTY_NEWLINE, babel_vty_port, VTY_NEWLINE, format_eui64(myid), VTY_NEWLINE, format_bool(allow_duplicates), VTY_NEWLINE, kernel_metric, VTY_NEWLINE); } quagga-0.99.22.4/babeld/babel_main.h0000644000175000017500000000454512177450262013676 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include "vty.h" extern struct timeval babel_now; /* current time */ extern struct thread_master *master; /* quagga's threads handler */ extern int debug; extern int resend_delay; extern unsigned char myid[8]; extern const unsigned char zeroes[16], ones[16]; extern int protocol_port; extern unsigned char protocol_group[16]; extern int protocol_socket; extern int kernel_socket; extern int max_request_hopcount; void babel_load_state_file(void); void show_babel_main_configuration (struct vty *vty); quagga-0.99.22.4/babeld/babel_zebra.c0000644000175000017500000002535612177450262014053 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ /* quagga's includes */ #include #include "command.h" #include "zclient.h" #include "stream.h" /* babel's includes*/ #include "babel_zebra.h" #include "babel_interface.h" #include "xroute.h" #include "util.h" void babelz_zebra_init(void); /* we must use a pointer because of zclient.c's functions (new, free). */ struct zclient *zclient; static int zebra_config_write (struct vty *vty); /* Debug types */ static struct { int type; int str_min_len; const char *str; } debug_type[] = { {BABEL_DEBUG_COMMON, 1, "common"}, {BABEL_DEBUG_KERNEL, 1, "kernel"}, {BABEL_DEBUG_FILTER, 1, "filter"}, {BABEL_DEBUG_TIMEOUT, 1, "timeout"}, {BABEL_DEBUG_IF, 1, "interface"}, {BABEL_DEBUG_ROUTE, 1, "route"}, {BABEL_DEBUG_ALL, 1, "all"}, {0, 0, NULL} }; /* Zebra node structure. */ struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", 1 /* vtysh? yes */ }; /* Zebra route add and delete treatment (ipv6). */ static int babel_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex = -1; struct in6_addr nexthop; struct prefix_ipv6 prefix; s = zclient->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); memset (&api, 0, sizeof(struct zapi_ipv6)); memset (&prefix, 0, sizeof (struct prefix_ipv6)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ prefix.family = AF_INET6; prefix.prefixlen = stream_getc (s); stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, sizeof(nexthop)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop); else babel_ipv6_route_delete(&api, &prefix, ifindex); return 0; } static int babel_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex = -1; struct in_addr nexthop; struct prefix_ipv4 prefix; s = zclient->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in_addr)); memset (&api, 0, sizeof(struct zapi_ipv4)); memset (&prefix, 0, sizeof (struct prefix_ipv4)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ prefix.family = AF_INET; prefix.prefixlen = stream_getc (s); stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, sizeof(nexthop)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) { babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop); } else { babel_ipv4_route_delete(&api, &prefix, ifindex); } return 0; } /* [Babel Command] */ DEFUN (babel_redistribute_type, babel_redistribute_type_cmd, "redistribute " QUAGGA_REDIST_STR_BABELD, "Redistribute\n" QUAGGA_REDIST_HELP_STR_BABELD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) type = proto_redistnum(AFI_IP, 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); return CMD_SUCCESS; } /* [Babel Command] */ DEFUN (no_babel_redistribute_type, no_babel_redistribute_type_cmd, "no redistribute " QUAGGA_REDIST_STR_BABELD, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_BABELD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) type = proto_redistnum(AFI_IP, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); /* perhaps should we remove xroutes having the same type... */ return CMD_SUCCESS; } #ifndef NO_DEBUG /* [Babel Command] */ DEFUN (debug_babel, debug_babel_cmd, "debug babel (common|kernel|filter|timeout|interface|route|all)", "Enable debug messages for specific or all part.\n" "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" "Timeout messages\n" "Interface messages\n" "Route messages\n" "All messages\n") { int i; for(i = 0; debug_type[i].str != NULL; i++) { if (strncmp (debug_type[i].str, argv[0], debug_type[i].str_min_len) == 0) { debug |= debug_type[i].type; return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } /* [Babel Command] */ DEFUN (no_debug_babel, no_debug_babel_cmd, "no debug babel (common|kernel|filter|timeout|interface|route|all)", NO_STR "Disable debug messages for specific or all part.\n" "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" "Timeout messages\n" "Interface messages\n" "Route messages\n" "All messages\n") { int i; for (i = 0; debug_type[i].str; i++) { if (strncmp(debug_type[i].str, argv[0], debug_type[i].str_min_len) == 0) { debug &= ~debug_type[i].type; return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } #endif /* NO_DEBUG */ /* Output "debug" statement lines, if necessary. */ int debug_babel_config_write (struct vty * vty) { #ifdef NO_DEBUG return 0; #else int i, lines = 0; if (debug == BABEL_DEBUG_ALL) { vty_out (vty, "debug babel all%s", VTY_NEWLINE); lines++; } else for (i = 0; debug_type[i].str != NULL; i++) if ( debug_type[i].type != BABEL_DEBUG_ALL && CHECK_FLAG (debug, debug_type[i].type) ) { vty_out (vty, "debug babel %s%s", debug_type[i].str, VTY_NEWLINE); lines++; } if (lines) { vty_out (vty, "!%s", VTY_NEWLINE); lines++; } return lines; #endif /* NO_DEBUG */ } void babelz_zebra_init(void) { zclient = zclient_new(); zclient_init(zclient, ZEBRA_ROUTE_BABEL); zclient->interface_add = babel_interface_add; zclient->interface_delete = babel_interface_delete; zclient->interface_up = babel_interface_up; zclient->interface_down = babel_interface_down; zclient->interface_address_add = babel_interface_address_add; zclient->interface_address_delete = babel_interface_address_delete; zclient->ipv4_route_add = babel_zebra_read_ipv4; zclient->ipv4_route_delete = babel_zebra_read_ipv4; zclient->ipv6_route_add = babel_zebra_read_ipv6; zclient->ipv6_route_delete = babel_zebra_read_ipv6; install_node (&zebra_node, zebra_config_write); install_element(BABEL_NODE, &babel_redistribute_type_cmd); install_element(BABEL_NODE, &no_babel_redistribute_type_cmd); install_element(ENABLE_NODE, &debug_babel_cmd); install_element(ENABLE_NODE, &no_debug_babel_cmd); install_element(CONFIG_NODE, &debug_babel_cmd); install_element(CONFIG_NODE, &no_debug_babel_cmd); } static int zebra_config_write (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } else if (! zclient->redist[ZEBRA_ROUTE_BABEL]) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute babel%s", VTY_NEWLINE); return 1; } return 0; } void babel_zebra_close_connexion(void) { zclient_stop(zclient); } quagga-0.99.22.4/babeld/babel_zebra.h0000644000175000017500000000406512177450262014052 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #ifndef BABEL_ZEBRA_H #define BABEL_ZEBRA_H #include "vty.h" extern struct zclient *zclient; void babelz_zebra_init(void); void babel_zebra_close_connexion(void); extern int debug_babel_config_write (struct vty *); #endif quagga-0.99.22.4/babeld/babeld.c0000644000175000017500000005223612177450262013031 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include #include "command.h" #include "prefix.h" #include "memory.h" #include "memtypes.h" #include "table.h" #include "distribute.h" #include "prefix.h" #include "filter.h" #include "plist.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "net.h" #include "kernel.h" #include "babel_interface.h" #include "neighbour.h" #include "route.h" #include "message.h" #include "resend.h" #include "babel_filter.h" #include "babel_zebra.h" static int babel_init_routing_process(struct thread *thread); static void babel_get_myid(void); static void babel_initial_noise(void); static int babel_read_protocol (struct thread *thread); static int babel_main_loop(struct thread *thread); static void babel_set_timer(struct timeval *timeout); static void babel_fill_with_next_timeout(struct timeval *tv); /* Informations relative to the babel running daemon. */ static struct babel *babel_routing_process = NULL; static unsigned char *receive_buffer = NULL; static int receive_buffer_size = 0; /* timeouts */ struct timeval check_neighbours_timeout; static time_t expiry_time; static time_t source_expiry_time; /* Babel node structure. */ static struct cmd_node cmd_babel_node = { .node = BABEL_NODE, .prompt = "%s(config-router)# ", .vtysh = 1, }; /* print current babel configuration on vty */ static int babel_config_write (struct vty *vty) { int lines = 0; int i; /* list enabled debug modes */ lines += debug_babel_config_write (vty); if (!babel_routing_process) return lines; vty_out (vty, "router babel%s", VTY_NEWLINE); if (resend_delay != BABEL_DEFAULT_RESEND_DELAY) { vty_out (vty, " babel resend-delay %u%s", resend_delay, VTY_NEWLINE); lines++; } /* list enabled interfaces */ lines = 1 + babel_enable_if_config_write (vty); /* list redistributed protocols */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) { vty_out (vty, " redistribute %s%s", zebra_route_string (i), VTY_NEWLINE); lines++; } return lines; } static int babel_create_routing_process (void) { assert (babel_routing_process == NULL); /* Allocaste Babel instance. */ babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel)); /* Initialize timeouts */ gettime(&babel_now); expiry_time = babel_now.tv_sec + roughly(30); source_expiry_time = babel_now.tv_sec + roughly(300); /* Make socket for Babel protocol. */ protocol_socket = babel_socket(protocol_port); if (protocol_socket < 0) { zlog_err("Couldn't create link local socket: %s", safe_strerror(errno)); goto fail; } /* Threads. */ babel_routing_process->t_read = thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); /* wait a little: zebra will announce interfaces, addresses, routes... */ babel_routing_process->t_update = thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L); return 0; fail: XFREE(MTYPE_BABEL, babel_routing_process); babel_routing_process = NULL; return -1; } /* thread reading entries form others babel daemons */ static int babel_read_protocol (struct thread *thread) { int rc; struct interface *ifp = NULL; struct sockaddr_in6 sin6; struct listnode *linklist_node = NULL; assert(babel_routing_process != NULL); assert(protocol_socket >= 0); rc = babel_recv(protocol_socket, receive_buffer, receive_buffer_size, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) { if(errno != EAGAIN && errno != EINTR) { zlog_err("recv: %s", safe_strerror(errno)); } } else { FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; if(ifp->ifindex == sin6.sin6_scope_id) { parse_packet((unsigned char*)&sin6.sin6_addr, ifp, receive_buffer, rc); break; } } } /* re-add thread */ babel_routing_process->t_read = thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); return 0; } /* Zebra will give some information, especially about interfaces. This function must be call with a litte timeout wich may give zebra the time to do his job, making these inits have sense. */ static int babel_init_routing_process(struct thread *thread) { myseqno = (random() & 0xFFFF); babel_get_myid(); babel_load_state_file(); debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); babel_initial_noise(); babel_main_loop(thread);/* this function self-add to the t_update thread */ return 0; } /* fill "myid" with an unique id (only if myid != {0}). */ static void babel_get_myid(void) { struct interface *ifp = NULL; struct listnode *linklist_node = NULL; int rc; int i; /* if we already have an id (from state file), we return. */ if (memcmp(myid, zeroes, 8) != 0) { return; } FOR_ALL_INTERFACES(ifp, linklist_node) { /* ifp->ifindex is not necessarily valid at this point */ int ifindex = if_nametoindex(ifp->name); if(ifindex > 0) { unsigned char eui[8]; rc = if_eui64(ifp->name, ifindex, eui); if(rc < 0) continue; memcpy(myid, eui, 8); return; } } /* We failed to get a global EUI64 from the interfaces we were given. Let's try to find an interface with a MAC address. */ for(i = 1; i < 256; i++) { char buf[IF_NAMESIZE], *ifname; unsigned char eui[8]; ifname = if_indextoname(i, buf); if(ifname == NULL) continue; rc = if_eui64(ifname, i, eui); if(rc < 0) continue; memcpy(myid, eui, 8); return; } zlog_err("Warning: couldn't find router id -- using random value."); rc = read_random_bytes(myid, 8); if(rc < 0) { zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno)); exit(1); } /* Clear group and global bits */ myid[0] &= ~3; } /* Make some noise so that others notice us, and send retractions in case we were restarted recently */ static void babel_initial_noise(void) { struct interface *ifp = NULL; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; /* Apply jitter before we send the first message. */ usleep(roughly(10000)); gettime(&babel_now); send_hello(ifp); send_wildcard_retraction(ifp); } FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; usleep(roughly(10000)); gettime(&babel_now); send_hello(ifp); send_wildcard_retraction(ifp); send_self_update(ifp); send_request(ifp, NULL, 0); flushupdates(ifp); flushbuf(ifp); } } /* Delete all the added babel routes, make babeld only speak to zebra. */ static void babel_clean_routing_process() { flush_all_routes(); babel_interface_close_all(); /* cancel threads */ if (babel_routing_process->t_read != NULL) { thread_cancel(babel_routing_process->t_read); } if (babel_routing_process->t_update != NULL) { thread_cancel(babel_routing_process->t_update); } XFREE(MTYPE_BABEL, babel_routing_process); babel_routing_process = NULL; } /* Function used with timeout. */ static int babel_main_loop(struct thread *thread) { struct timeval tv; struct interface *ifp = NULL; struct listnode *linklist_node = NULL; while(1) { gettime(&babel_now); /* timeouts --------------------------------------------------------- */ /* get the next timeout */ babel_fill_with_next_timeout(&tv); /* if there is no timeout, we must wait. */ if(timeval_compare(&tv, &babel_now) > 0) { timeval_minus(&tv, &tv, &babel_now); debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs", tv.tv_sec * 1000 + tv.tv_usec / 1000); /* it happens often to have less than 1 ms, it's bad. */ timeval_add_msec(&tv, &tv, 300); babel_set_timer(&tv); return 0; } gettime(&babel_now); /* update database -------------------------------------------------- */ if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) { int msecs; msecs = check_neighbours(); msecs = MAX(msecs, 10); schedule_neighbours_check(msecs, 1); } if(babel_now.tv_sec >= expiry_time) { expire_routes(); expire_resend(); expiry_time = babel_now.tv_sec + roughly(30); } if(babel_now.tv_sec >= source_expiry_time) { expire_sources(); source_expiry_time = babel_now.tv_sec + roughly(300); } FOR_ALL_INTERFACES(ifp, linklist_node) { babel_interface_nfo *babel_ifp = NULL; if(!if_up(ifp)) continue; babel_ifp = babel_get_if_nfo(ifp); if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0) send_hello(ifp); if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0) send_update(ifp, 0, NULL, 0); if(timeval_compare(&babel_now, &babel_ifp->update_flush_timeout) >= 0) flushupdates(ifp); } if(resend_time.tv_sec != 0) { if(timeval_compare(&babel_now, &resend_time) >= 0) do_resend(); } if(unicast_flush_timeout.tv_sec != 0) { if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0) flush_unicast(1); } FOR_ALL_INTERFACES(ifp, linklist_node) { babel_interface_nfo *babel_ifp = NULL; if(!if_up(ifp)) continue; babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->flush_timeout.tv_sec != 0) { if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0) flushbuf(ifp); } } } assert(0); /* this line should never be reach */ } static void printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname) { static struct timeval curr_tv; static char buffer[200]; static const char *curr_tag = NULL; switch (cmd) { case 0: /* reset timeval */ curr_tv = *tv; if(ifname != NULL) { snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); curr_tag = buffer; } else { curr_tag = tag; } break; case 1: /* take the min */ if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */ break; } if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec && tv->tv_usec < curr_tv.tv_usec)) { curr_tv = *tv; if(ifname != NULL) { snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); curr_tag = buffer; } else { curr_tag = tag; } } break; case 2: /* print message */ debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag); break; default: break; } } static void babel_fill_with_next_timeout(struct timeval *tv) { #if (defined NO_DEBUG) #define printIfMin(a,b,c,d) #else #define printIfMin(a,b,c,d) \ if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);} struct interface *ifp = NULL; struct listnode *linklist_node = NULL; *tv = check_neighbours_timeout; printIfMin(tv, 0, "check_neighbours_timeout", NULL); timeval_min_sec(tv, expiry_time); printIfMin(tv, 1, "expiry_time", NULL); timeval_min_sec(tv, source_expiry_time); printIfMin(tv, 1, "source_expiry_time", NULL); timeval_min(tv, &resend_time); printIfMin(tv, 1, "resend_time", NULL); FOR_ALL_INTERFACES(ifp, linklist_node) { babel_interface_nfo *babel_ifp = NULL; if(!if_up(ifp)) continue; babel_ifp = babel_get_if_nfo(ifp); timeval_min(tv, &babel_ifp->flush_timeout); printIfMin(tv, 1, "flush_timeout", ifp->name); timeval_min(tv, &babel_ifp->hello_timeout); printIfMin(tv, 1, "hello_timeout", ifp->name); timeval_min(tv, &babel_ifp->update_timeout); printIfMin(tv, 1, "update_timeout", ifp->name); timeval_min(tv, &babel_ifp->update_flush_timeout); printIfMin(tv, 1, "update_flush_timeout",ifp->name); } timeval_min(tv, &unicast_flush_timeout); printIfMin(tv, 1, "unicast_flush_timeout", NULL); printIfMin(tv, 2, NULL, NULL); #undef printIfMin #endif } /* set the t_update thread of the babel routing process to be launch in 'timeout' (approximate at the milisecond) */ static void babel_set_timer(struct timeval *timeout) { long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; if (babel_routing_process->t_update != NULL) { thread_cancel(babel_routing_process->t_update); } babel_routing_process->t_update = thread_add_timer_msec(master, &babel_main_loop, NULL, msecs); } /* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */ void schedule_neighbours_check(int msecs, int override) { struct timeval timeout; timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2)); if(override) check_neighbours_timeout = timeout; else timeval_min(&check_neighbours_timeout, &timeout); } int resize_receive_buffer(int size) { if(size <= receive_buffer_size) return 0; if(receive_buffer == NULL) { receive_buffer = malloc(size); if(receive_buffer == NULL) { zlog_err("malloc(receive_buffer): %s", safe_strerror(errno)); return -1; } receive_buffer_size = size; } else { unsigned char *new; new = realloc(receive_buffer, size); if(new == NULL) { zlog_err("realloc(receive_buffer): %s", safe_strerror(errno)); return -1; } receive_buffer = new; receive_buffer_size = size; } return 1; } static void babel_distribute_update (struct distribute *dist) { struct interface *ifp; babel_interface_nfo *babel_ifp; struct access_list *alist; struct prefix_list *plist; if (! dist->ifname) return; ifp = if_lookup_by_name (dist->ifname); if (ifp == NULL) return; babel_ifp = babel_get_if_nfo(ifp); if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); if (alist) babel_ifp->list[BABEL_FILTER_IN] = alist; else babel_ifp->list[BABEL_FILTER_IN] = NULL; } else { babel_ifp->list[BABEL_FILTER_IN] = NULL; } if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); if (alist) babel_ifp->list[BABEL_FILTER_OUT] = alist; else babel_ifp->list[BABEL_FILTER_OUT] = NULL; } else { babel_ifp->list[BABEL_FILTER_OUT] = NULL; } if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); if (plist) babel_ifp->prefix[BABEL_FILTER_IN] = plist; else babel_ifp->prefix[BABEL_FILTER_IN] = NULL; } else { babel_ifp->prefix[BABEL_FILTER_IN] = NULL; } if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); if (plist) babel_ifp->prefix[BABEL_FILTER_OUT] = plist; else babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; } else { babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; } } static void babel_distribute_update_interface (struct interface *ifp) { struct distribute *dist; dist = distribute_lookup (ifp->name); if (dist) babel_distribute_update (dist); } /* Update all interface's distribute list. */ static void babel_distribute_update_all (struct prefix_list *notused) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) babel_distribute_update_interface (ifp); } static void babel_distribute_update_all_wrapper (struct access_list *notused) { babel_distribute_update_all(NULL); } /* [Command] */ DEFUN (router_babel, router_babel_cmd, "router babel", "Enable a routing process\n" "Make Babel instance command\n" "No attributes\n") { int ret; vty->node = BABEL_NODE; if (!babel_routing_process) { ret = babel_create_routing_process (); /* Notice to user we couldn't create Babel. */ if (ret < 0) { zlog_warn ("can't create Babel"); return CMD_WARNING; } } return CMD_SUCCESS; } /* [Command] */ DEFUN (no_router_babel, no_router_babel_cmd, "no router babel", NO_STR "Disable a routing process\n" "Remove Babel instance command\n" "No attributes\n") { if(babel_routing_process) babel_clean_routing_process(); return CMD_SUCCESS; } /* [Babel Command] */ DEFUN (babel_set_resend_delay, babel_set_resend_delay_cmd, "babel resend-delay <20-655340>", "Babel commands\n" "Time before resending a message\n" "Milliseconds\n") { int interval; VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); resend_delay = interval; return CMD_SUCCESS; } void babeld_quagga_init(void) { install_node(&cmd_babel_node, &babel_config_write); install_element(CONFIG_NODE, &router_babel_cmd); install_element(CONFIG_NODE, &no_router_babel_cmd); install_default(BABEL_NODE); install_element(BABEL_NODE, &babel_set_resend_delay_cmd); babel_if_init(); /* Access list install. */ access_list_init (); access_list_add_hook (babel_distribute_update_all_wrapper); access_list_delete_hook (babel_distribute_update_all_wrapper); /* Prefix list initialize.*/ prefix_list_init (); prefix_list_add_hook (babel_distribute_update_all); prefix_list_delete_hook (babel_distribute_update_all); /* Distribute list install. */ distribute_list_init (BABEL_NODE); distribute_list_add_hook (babel_distribute_update); distribute_list_delete_hook (babel_distribute_update); } /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */ int input_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, const unsigned char *neigh, unsigned int ifindex) { return babel_filter(0, prefix, plen, ifindex); } int output_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, unsigned int ifindex) { return babel_filter(1, prefix, plen, ifindex); } /* There's no redistribute filter in Quagga -- the zebra daemon does its own filtering. */ int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto) { return 0; } quagga-0.99.22.4/babeld/babeld.conf.sample0000644000175000017500000000121712177450262015005 00000000000000debug babel common !debug babel kernel !debug babel filter !debug babel timeout !debug babel interface !debug babel route !debug babel all router babel ! network wlan0 ! network eth0 ! redistribute kernel ! no redistribute static ! The defaults are fine for a wireless interface !interface wlan0 ! A few optimisation tweaks are optional but recommended on a wired interface ! Disable link quality estimation, enable split horizon processing, and ! increase the hello and update intervals. !interface eth0 ! babel wired ! babel split-horizon ! babel hello-interval 12000 ! babel update-interval 36000 ! log file /var/log/quagga/babeld.log log stdout quagga-0.99.22.4/babeld/babeld.h0000644000175000017500000001045412177450262013032 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #ifndef BABEL_BABELD_H #define BABEL_BABELD_H #include #include "vty.h" #define INFINITY ((unsigned short)(~0)) #ifndef RTPROT_BABEL #define RTPROT_BABEL 42 #endif #define RTPROT_BABEL_LOCAL -2 #undef MAX #undef MIN #define MAX(x,y) ((x)<=(y)?(y):(x)) #define MIN(x,y) ((x)<=(y)?(x):(y)) #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* nothing */ #elif defined(__GNUC__) #define inline __inline #if (__GNUC__ >= 3) #define restrict __restrict #else #define restrict /**/ #endif #else #define inline /**/ #define restrict /**/ #endif #if defined(__GNUC__) && (__GNUC__ >= 3) #define ATTRIBUTE(x) __attribute__ (x) #define LIKELY(_x) __builtin_expect(!!(_x), 1) #define UNLIKELY(_x) __builtin_expect(!!(_x), 0) #else #define ATTRIBUTE(x) /**/ #define LIKELY(_x) !!(_x) #define UNLIKELY(_x) !!(_x) #endif #if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3) #define COLD __attribute__ ((cold)) #else #define COLD /**/ #endif #ifndef IF_NAMESIZE #include #include #endif #ifdef HAVE_VALGRIND #include #else #ifndef VALGRIND_MAKE_MEM_UNDEFINED #define VALGRIND_MAKE_MEM_UNDEFINED(a, b) do {} while(0) #endif #ifndef VALGRIND_CHECK_MEM_IS_DEFINED #define VALGRIND_CHECK_MEM_IS_DEFINED(a, b) do {} while(0) #endif #endif #define BABEL_VTY_PORT 2609 #define BABEL_DEFAULT_CONFIG "babeld.conf" #define BABEL_VERSION "0.1 for quagga" /* Values in milliseconds */ #define BABEL_DEFAULT_HELLO_INTERVAL 4000 #define BABEL_DEFAULT_UPDATE_INTERVAL 16000 #define BABEL_DEFAULT_RESEND_DELAY 2000 /* Babel socket. */ extern int protocol_socket; /* Babel structure. */ struct babel { /* Babel threads. */ struct thread *t_read; /* on Babel protocol's socket */ struct thread *t_update; /* timers */ }; extern void babeld_quagga_init(void); extern int input_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, const unsigned char *neigh, unsigned int ifindex); extern int output_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, unsigned int ifindex); extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto); extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); #endif /* BABEL_BABELD_H */ quagga-0.99.22.4/babeld/kernel.c0000644000175000017500000002351712177450262013100 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include #include #include #include "babeld.h" #include #include #include #include #include #include #include "prefix.h" #include "zclient.h" #include "kernel.h" #include "privs.h" #include "command.h" #include "vty.h" #include "memory.h" #include "thread.h" #include "util.h" #include "babel_interface.h" #include "babel_zebra.h" static int kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric); static int kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric); int kernel_interface_operational(struct interface *interface) { return if_is_operative(interface); } int kernel_interface_mtu(struct interface *interface) { return MIN(interface->mtu, interface->mtu6); } int kernel_interface_wireless(struct interface *interface) { return 0; } int kernel_route(int operation, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric) { int rc; int ipv4; /* Check that the protocol family is consistent. */ if(plen >= 96 && v4mapped(pref)) { if(!v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 1; } else { if(v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 0; } switch (operation) { case ROUTE_ADD: return ipv4 ? kernel_route_v4(1, pref, plen, gate, ifindex, metric): kernel_route_v6(1, pref, plen, gate, ifindex, metric); break; case ROUTE_FLUSH: return ipv4 ? kernel_route_v4(0, pref, plen, gate, ifindex, metric): kernel_route_v6(0, pref, plen, gate, ifindex, metric); break; case ROUTE_MODIFY: if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); rc = ipv4 ? kernel_route_v4(0, pref, plen, gate, ifindex, metric): kernel_route_v6(0, pref, plen, gate, ifindex, metric); if (rc < 0) return -1; rc = ipv4 ? kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); return rc; break; default: zlog_err("this should never appens (false value - kernel_route)"); assert(0); exit(1); break; } } static int kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric) { struct zapi_ipv4 api; /* quagga's communication system */ struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ struct in_addr babel_prefix_addr; /* babeld's prefix addr */ struct in_addr nexthop; /* next router to go */ struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_inaddr(&babel_prefix_addr, pref); uchar_to_inaddr(&nexthop, gate); /* make prefix structure */ memset (&quagga_prefix, 0, sizeof(quagga_prefix)); quagga_prefix.family = AF_INET; IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ apply_mask_ipv4(&quagga_prefix); api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; /* Unlike the native Linux and BSD interfaces, Quagga doesn't like there to be both and IPv4 nexthop and an ifindex. Omit the ifindex, and assume that the connected prefixes be set up correctly. */ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.ifindex_num = 0; if(metric >= KERNEL_INFINITY) { api.flags = ZEBRA_FLAG_BLACKHOLE; api.nexthop_num = 0; } else { api.nexthop_num = 1; api.nexthop = &nexthop_pointer; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; } debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", add ? "adding" : "removing" ); return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE, zclient, &quagga_prefix, &api); } static int kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv6 api; /* quagga's communication system */ struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ struct in6_addr nexthop; /* next router to go */ struct in6_addr *nexthop_pointer = &nexthop; /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_in6addr(&babel_prefix_addr, pref); uchar_to_in6addr(&nexthop, gate); /* make prefix structure */ memset (&quagga_prefix, 0, sizeof(quagga_prefix)); quagga_prefix.family = AF_INET6; IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); quagga_prefix.prefixlen = plen; apply_mask_ipv6(&quagga_prefix); api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if(metric >= KERNEL_INFINITY) { api.flags = ZEBRA_FLAG_BLACKHOLE; api.nexthop_num = 0; api.ifindex_num = 0; } else { api.nexthop_num = 1; api.nexthop = &nexthop_pointer; SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &tmp_ifindex; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; } debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", add ? "adding" : "removing" ); return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, zclient, &quagga_prefix, &api); } int if_eui64(char *ifname, int ifindex, unsigned char *eui) { struct interface *ifp = if_lookup_by_index(ifindex); if (ifp == NULL) { return -1; } #ifdef HAVE_STRUCT_SOCKADDR_DL u_char len = ifp->sdl.sdl_alen; char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen; #else u_char len = (u_char) ifp->hw_addr_len; char *tmp = (void*) ifp->hw_addr; #endif if (len == 8) { memcpy(eui, tmp, 8); eui[0] ^= 2; } else if (len == 6) { memcpy(eui, tmp, 3); eui[3] = 0xFF; eui[4] = 0xFE; memcpy(eui+5, tmp+3, 3); } else { return -1; } return 0; } /* Like gettimeofday, but returns monotonic time. If POSIX clocks are not available, falls back to gettimeofday but enforces monotonicity. */ int gettime(struct timeval *tv) { return quagga_gettime(QUAGGA_CLK_MONOTONIC, tv); } /* If /dev/urandom doesn't exist, this will fail with ENOENT, which the caller will deal with gracefully. */ int read_random_bytes(void *buf, size_t len) { int fd; int rc; fd = open("/dev/urandom", O_RDONLY); if(fd < 0) { rc = -1; } else { rc = read(fd, buf, len); if(rc < 0 || (unsigned) rc < len) rc = -1; close(fd); } return rc; } quagga-0.99.22.4/babeld/kernel.h0000644000175000017500000000536112177450262013102 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #include #include "babel_main.h" #include "if.h" #define KERNEL_INFINITY 0xFFFF struct kernel_route { unsigned char prefix[16]; int plen; int metric; unsigned int ifindex; int proto; unsigned char gw[16]; }; #define ROUTE_FLUSH 0 #define ROUTE_ADD 1 #define ROUTE_MODIFY 2 extern int export_table, import_table; int kernel_interface_operational(struct interface *interface); int kernel_interface_mtu(struct interface *interface); int kernel_interface_wireless(struct interface *interface); int kernel_route(int operation, const unsigned char *dest, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric); int if_eui64(char *ifname, int ifindex, unsigned char *eui); int gettime(struct timeval *tv); int read_random_bytes(void *buf, size_t len); quagga-0.99.22.4/babeld/message.c0000644000175000017500000014540412177450262013244 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #include #include "if.h" #include "babeld.h" #include "util.h" #include "net.h" #include "babel_interface.h" #include "source.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #include "resend.h" #include "message.h" #include "kernel.h" unsigned char packet_header[4] = {42, 2}; int split_horizon = 1; unsigned short myseqno = 0; struct timeval seqno_time = {0, 0}; #define UNICAST_BUFSIZE 1024 int unicast_buffered = 0; unsigned char *unicast_buffer = NULL; struct neighbour *unicast_neighbour = NULL; struct timeval unicast_flush_timeout = {0, 0}; static const unsigned char v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; /* Parse a network prefix, encoded in the somewhat baroque compressed representation used by Babel. Return the number of bytes parsed. */ static int network_prefix(int ae, int plen, unsigned int omitted, const unsigned char *p, const unsigned char *dp, unsigned int len, unsigned char *p_r) { unsigned pb; unsigned char prefix[16]; int ret = -1; if(plen >= 0) pb = (plen + 7) / 8; else if(ae == 1) pb = 4; else pb = 16; if(pb > 16) return -1; memset(prefix, 0, 16); switch(ae) { case 0: ret = 0; break; case 1: if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) return -1; memcpy(prefix, v4prefix, 12); if(omitted) { if (dp == NULL || !v4mapped(dp)) return -1; memcpy(prefix, dp, 12 + omitted); } if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); ret = pb - omitted; break; case 2: if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; if(omitted) { if (dp == NULL || v4mapped(dp)) return -1; memcpy(prefix, dp, omitted); } if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); ret = pb - omitted; break; case 3: if(pb > 8 && len < pb - 8) return -1; prefix[0] = 0xfe; prefix[1] = 0x80; if(pb > 8) memcpy(prefix + 8, p, pb - 8); ret = pb - 8; break; default: return -1; } mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); return ret; } static void parse_route_attributes(const unsigned char *a, int alen, unsigned char *channels) { int type, len, i = 0; while(i < alen) { type = a[i]; if(type == 0) { i++; continue; } if(i + 1 > alen) { fprintf(stderr, "Received truncated attributes.\n"); return; } len = a[i + 1]; if(i + len > alen) { fprintf(stderr, "Received truncated attributes.\n"); return; } if(type == 1) { /* Nothing. */ } else if(type == 2) { if(len > DIVERSITY_HOPS) { fprintf(stderr, "Received overlong channel information (%d > %d).\n", len, DIVERSITY_HOPS); len = DIVERSITY_HOPS; } if(memchr(a + i + 2, 0, len) != NULL) { /* 0 is reserved. */ fprintf(stderr, "Channel information contains 0!"); return; } memset(channels, 0, DIVERSITY_HOPS); memcpy(channels, a + i + 2, len); } else { fprintf(stderr, "Received unknown route attribute %d.\n", type); } i += len + 2; } } static int network_address(int ae, const unsigned char *a, unsigned int len, unsigned char *a_r) { return network_prefix(ae, -1, 0, a, NULL, len, a_r); } static int channels_len(unsigned char *channels) { unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS); return p ? (p - channels) : DIVERSITY_HOPS; } void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen) { int i; const unsigned char *message; unsigned char type, len; int bodylen; struct neighbour *neigh; int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0, have_v4_nh = 0, have_v6_nh = 0; unsigned char router_id[8], v4_prefix[16], v6_prefix[16], v4_nh[16], v6_nh[16]; if(!linklocal(from)) { zlog_err("Received packet from non-local address %s.", format_address(from)); return; } if(packet[0] != 42) { zlog_err("Received malformed packet on %s from %s.", ifp->name, format_address(from)); return; } if(packet[1] != 2) { zlog_err("Received packet with unknown version %d on %s from %s.", packet[1], ifp->name, format_address(from)); return; } neigh = find_neighbour(from, ifp); if(neigh == NULL) { zlog_err("Couldn't allocate neighbour."); return; } DO_NTOHS(bodylen, packet + 2); if(bodylen + 4 > packetlen) { zlog_err("Received truncated packet (%d + 4 > %d).", bodylen, packetlen); bodylen = packetlen - 4; } i = 0; while(i < bodylen) { message = packet + 4 + i; type = message[0]; if(type == MESSAGE_PAD1) { debugf(BABEL_DEBUG_COMMON,"Received pad1 from %s on %s.", format_address(from), ifp->name); i++; continue; } if(i + 1 > bodylen) { zlog_err("Received truncated message."); break; } len = message[1]; if(i + len > bodylen) { zlog_err("Received truncated message."); break; } if(type == MESSAGE_PADN) { debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.", len, format_address(from), ifp->name); } else if(type == MESSAGE_ACK_REQ) { unsigned short nonce, interval; if(len < 6) goto fail; DO_NTOHS(nonce, message + 4); DO_NTOHS(interval, message + 6); debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.", nonce, interval, format_address(from), ifp->name); send_ack(neigh, nonce, interval); } else if(type == MESSAGE_ACK) { debugf(BABEL_DEBUG_COMMON,"Received ack from %s on %s.", format_address(from), ifp->name); /* Nothing right now */ } else if(type == MESSAGE_HELLO) { unsigned short seqno, interval; int changed; if(len < 6) goto fail; DO_NTOHS(seqno, message + 4); DO_NTOHS(interval, message + 6); debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", seqno, interval, format_address(from), ifp->name); changed = update_neighbour(neigh, seqno, interval); update_neighbour_metric(neigh, changed); if(interval > 0) schedule_neighbours_check(interval * 10, 0); } else if(type == MESSAGE_IHU) { unsigned short txcost, interval; unsigned char address[16]; int rc; if(len < 6) goto fail; DO_NTOHS(txcost, message + 4); DO_NTOHS(interval, message + 6); rc = network_address(message[2], message + 8, len - 6, address); if(rc < 0) goto fail; debugf(BABEL_DEBUG_COMMON,"Received ihu %d (%d) from %s on %s for %s.", txcost, interval, format_address(from), ifp->name, format_address(address)); if(message[2] == 0 || is_interface_ll_address(ifp, address)) { int changed = txcost != neigh->txcost; neigh->txcost = txcost; neigh->ihu_time = babel_now; neigh->ihu_interval = interval; update_neighbour_metric(neigh, changed); if(interval > 0) schedule_neighbours_check(interval * 10 * 3, 0); } } else if(type == MESSAGE_ROUTER_ID) { if(len < 10) { have_router_id = 0; goto fail; } memcpy(router_id, message + 4, 8); have_router_id = 1; debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.", format_eui64(router_id), format_address(from), ifp->name); } else if(type == MESSAGE_NH) { unsigned char nh[16]; int rc; if(len < 2) { have_v4_nh = 0; have_v6_nh = 0; goto fail; } rc = network_address(message[2], message + 4, len - 2, nh); if(rc < 0) { have_v4_nh = 0; have_v6_nh = 0; goto fail; } debugf(BABEL_DEBUG_COMMON,"Received nh %s (%d) from %s on %s.", format_address(nh), message[2], format_address(from), ifp->name); if(message[2] == 1) { memcpy(v4_nh, nh, 16); have_v4_nh = 1; } else { memcpy(v6_nh, nh, 16); have_v6_nh = 1; } } else if(type == MESSAGE_UPDATE) { unsigned char prefix[16], *nh; unsigned char plen; unsigned char channels[DIVERSITY_HOPS]; unsigned short interval, seqno, metric; int rc, parsed_len; if(len < 10) { if(len < 2 || message[3] & 0x80) have_v4_prefix = have_v6_prefix = 0; goto fail; } DO_NTOHS(interval, message + 6); DO_NTOHS(seqno, message + 8); DO_NTOHS(metric, message + 10); if(message[5] == 0 || (message[3] == 1 ? have_v4_prefix : have_v6_prefix)) rc = network_prefix(message[2], message[4], message[5], message + 12, message[2] == 1 ? v4_prefix : v6_prefix, len - 10, prefix); else rc = -1; if(rc < 0) { if(message[3] & 0x80) have_v4_prefix = have_v6_prefix = 0; goto fail; } parsed_len = 10 + rc; plen = message[4] + (message[2] == 1 ? 96 : 0); if(message[3] & 0x80) { if(message[2] == 1) { memcpy(v4_prefix, prefix, 16); have_v4_prefix = 1; } else { memcpy(v6_prefix, prefix, 16); have_v6_prefix = 1; } } if(message[3] & 0x40) { if(message[2] == 1) { memset(router_id, 0, 4); memcpy(router_id + 4, prefix + 12, 4); } else { memcpy(router_id, prefix + 8, 8); } have_router_id = 1; } if(!have_router_id && message[2] != 0) { zlog_err("Received prefix with no router id."); goto fail; } debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", (message[3] & 0x80) ? "/prefix" : "", (message[3] & 0x40) ? "/id" : "", format_prefix(prefix, plen), format_address(from), ifp->name); if(message[2] == 0) { if(metric < 0xFFFF) { zlog_err("Received wildcard update with finite metric."); goto done; } retract_neighbour_routes(neigh); goto done; } else if(message[2] == 1) { if(!have_v4_nh) goto fail; nh = v4_nh; } else if(have_v6_nh) { nh = v6_nh; } else { nh = neigh->address; } if(message[2] == 1) { if(!babel_get_if_nfo(ifp)->ipv4) goto done; } if((ifp->flags & BABEL_IF_FARAWAY)) { channels[0] = 0; } else { /* This will be overwritten by parse_route_attributes below. */ if(metric < 256) { /* Assume non-interfering (wired) link. */ channels[0] = 0; } else { /* Assume interfering. */ channels[0] = BABEL_IF_CHANNEL_INTERFERING; channels[1] = 0; } if(parsed_len < len) parse_route_attributes(message + 2 + parsed_len, len - parsed_len, channels); } update_route(router_id, prefix, plen, seqno, metric, interval, neigh, nh, channels, channels_len(channels)); } else if(type == MESSAGE_REQUEST) { unsigned char prefix[16], plen; int rc; if(len < 2) goto fail; rc = network_prefix(message[2], message[3], 0, message + 4, NULL, len - 2, prefix); if(rc < 0) goto fail; plen = message[3] + (message[2] == 1 ? 96 : 0); debugf(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.", message[2] == 0 ? "any" : format_prefix(prefix, plen), format_address(from), ifp->name); if(message[2] == 0) { struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp); /* If a neighbour is requesting a full route dump from us, we might as well send it an IHU. */ send_ihu(neigh, NULL); /* Since nodes send wildcard requests on boot, booting a large number of nodes at the same time may cause an update storm. Ignore a wildcard request that happens shortly after we sent a full update. */ if(babel_ifp->last_update_time < (time_t)(babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1))) send_update(neigh->ifp, 0, NULL, 0); } else { send_update(neigh->ifp, 0, prefix, plen); } } else if(type == MESSAGE_MH_REQUEST) { unsigned char prefix[16], plen; unsigned short seqno; int rc; if(len < 14) goto fail; DO_NTOHS(seqno, message + 4); rc = network_prefix(message[2], message[3], 0, message + 16, NULL, len - 14, prefix); if(rc < 0) goto fail; plen = message[3] + (message[2] == 1 ? 96 : 0); debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).", message[6], format_prefix(prefix, plen), format_address(from), ifp->name, format_eui64(message + 8), seqno); handle_request(neigh, prefix, plen, message[6], seqno, message + 8); } else { debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.", type, format_address(from), ifp->name); } done: i += len + 2; continue; fail: zlog_err("Couldn't parse packet (%d, %d) from %s on %s.", message[0], message[1], format_address(from), ifp->name); goto done; } return; } /* Under normal circumstances, there are enough moderation mechanisms elsewhere in the protocol to make sure that this last-ditch check should never trigger. But I'm superstitious. */ static int check_bucket(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bucket <= 0) { int seconds = babel_now.tv_sec - babel_ifp->bucket_time; if(seconds > 0) { babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX, seconds * BUCKET_TOKENS_PER_SEC); } /* Reset bucket time unconditionally, in case clock is stepped. */ babel_ifp->bucket_time = babel_now.tv_sec; } if(babel_ifp->bucket > 0) { babel_ifp->bucket--; return 1; } else { return 0; } } void flushbuf(struct interface *ifp) { int rc; struct sockaddr_in6 sin6; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); assert(babel_ifp->buffered <= babel_ifp->bufsize); flushupdates(ifp); if(babel_ifp->buffered > 0) { debugf(BABEL_DEBUG_COMMON," (flushing %d buffered bytes on %s)", babel_ifp->buffered, ifp->name); if(check_bucket(ifp)) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, protocol_group, 16); sin6.sin6_port = htons(protocol_port); sin6.sin6_scope_id = ifp->ifindex; DO_HTONS(packet_header + 2, babel_ifp->buffered); rc = babel_send(protocol_socket, packet_header, sizeof(packet_header), babel_ifp->sendbuf, babel_ifp->buffered, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) zlog_err("send: %s", safe_strerror(errno)); } else { zlog_err("Warning: bucket full, dropping packet to %s.", ifp->name); } } VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); babel_ifp->buffered = 0; babel_ifp->have_buffered_hello = 0; babel_ifp->have_buffered_id = 0; babel_ifp->have_buffered_nh = 0; babel_ifp->have_buffered_prefix = 0; babel_ifp->flush_timeout.tv_sec = 0; babel_ifp->flush_timeout.tv_usec = 0; } static void schedule_flush(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned msecs = jitter(babel_ifp, 0); if(babel_ifp->flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) return; set_timeout(&babel_ifp->flush_timeout, msecs); } static void schedule_flush_now(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); /* Almost now */ unsigned msecs = roughly(10); if(babel_ifp->flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) return; set_timeout(&babel_ifp->flush_timeout, msecs); } static void schedule_unicast_flush(unsigned msecs) { if(!unicast_neighbour) return; if(unicast_flush_timeout.tv_sec != 0 && timeval_minus_msec(&unicast_flush_timeout, &babel_now) < msecs) return; unicast_flush_timeout.tv_usec = (babel_now.tv_usec + msecs * 1000) %1000000; unicast_flush_timeout.tv_sec = babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000; } static void ensure_space(struct interface *ifp, int space) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bufsize - babel_ifp->buffered < space) flushbuf(ifp); } static void start_message(struct interface *ifp, int type, int len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bufsize - babel_ifp->buffered < len + 2) flushbuf(ifp); babel_ifp->sendbuf[babel_ifp->buffered++] = type; babel_ifp->sendbuf[babel_ifp->buffered++] = len; } static void end_message(struct interface *ifp, int type, int bytes) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); assert(babel_ifp->buffered >= bytes + 2 && babel_ifp->sendbuf[babel_ifp->buffered - bytes - 2] == type && babel_ifp->sendbuf[babel_ifp->buffered - bytes - 1] == bytes); schedule_flush(ifp); } static void accumulate_byte(struct interface *ifp, unsigned char value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); babel_ifp->sendbuf[babel_ifp->buffered++] = value; } static void accumulate_short(struct interface *ifp, unsigned short value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value); babel_ifp->buffered += 2; } static void accumulate_bytes(struct interface *ifp, const unsigned char *value, unsigned len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); memcpy(babel_ifp->sendbuf + babel_ifp->buffered, value, len); babel_ifp->buffered += len; } static int start_unicast_message(struct neighbour *neigh, int type, int len) { if(unicast_neighbour) { if(neigh != unicast_neighbour || unicast_buffered + len + 2 >= MIN(UNICAST_BUFSIZE, babel_get_if_nfo(neigh->ifp)->bufsize)) flush_unicast(0); } if(!unicast_buffer) unicast_buffer = malloc(UNICAST_BUFSIZE); if(!unicast_buffer) { zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno)); return -1; } unicast_neighbour = neigh; unicast_buffer[unicast_buffered++] = type; unicast_buffer[unicast_buffered++] = len; return 1; } static void end_unicast_message(struct neighbour *neigh, int type, int bytes) { assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 && unicast_buffer[unicast_buffered - bytes - 2] == type && unicast_buffer[unicast_buffered - bytes - 1] == bytes); schedule_unicast_flush(jitter(babel_get_if_nfo(neigh->ifp), 0)); } static void accumulate_unicast_byte(struct neighbour *neigh, unsigned char value) { unicast_buffer[unicast_buffered++] = value; } static void accumulate_unicast_short(struct neighbour *neigh, unsigned short value) { DO_HTONS(unicast_buffer + unicast_buffered, value); unicast_buffered += 2; } static void accumulate_unicast_bytes(struct neighbour *neigh, const unsigned char *value, unsigned len) { memcpy(unicast_buffer + unicast_buffered, value, len); unicast_buffered += len; } void send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) { int rc; debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.", nonce, format_address(neigh->address), neigh->ifp->name); rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; accumulate_unicast_short(neigh, nonce); end_unicast_message(neigh, MESSAGE_ACK, 2); /* Roughly yields a value no larger than 3/2, so this meets the deadline */ schedule_unicast_flush(roughly(interval * 6)); } void send_hello_noupdate(struct interface *ifp, unsigned interval) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); /* This avoids sending multiple hellos in a single packet, which breaks link quality estimation. */ if(babel_ifp->have_buffered_hello) flushbuf(ifp); babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1); set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); if(!if_up(ifp)) return; debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.", babel_ifp->hello_seqno, interval, ifp->name); start_message(ifp, MESSAGE_HELLO, 6); accumulate_short(ifp, 0); accumulate_short(ifp, babel_ifp->hello_seqno); accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); end_message(ifp, MESSAGE_HELLO, 6); babel_ifp->have_buffered_hello = 1; } void send_hello(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ if(babel_ifp->hello_seqno % 3 == 0) send_ihu(NULL, ifp); else send_marginal_ihu(ifp); } void flush_unicast(int dofree) { struct sockaddr_in6 sin6; int rc; if(unicast_buffered == 0) goto done; if(!if_up(unicast_neighbour->ifp)) goto done; /* Preserve ordering of messages */ flushbuf(unicast_neighbour->ifp); if(check_bucket(unicast_neighbour->ifp)) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, unicast_neighbour->address, 16); sin6.sin6_port = htons(protocol_port); sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex; DO_HTONS(packet_header + 2, unicast_buffered); rc = babel_send(protocol_socket, packet_header, sizeof(packet_header), unicast_buffer, unicast_buffered, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) zlog_err("send(unicast): %s", safe_strerror(errno)); } else { zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.", format_address(unicast_neighbour->address), unicast_neighbour->ifp->name); } done: VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE); unicast_buffered = 0; if(dofree && unicast_buffer) { free(unicast_buffer); unicast_buffer = NULL; } unicast_neighbour = NULL; unicast_flush_timeout.tv_sec = 0; unicast_flush_timeout.tv_usec = 0; } static void really_send_update(struct interface *ifp, const unsigned char *id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short metric, unsigned char *channels, int channels_len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); int add_metric, v4, real_plen, omit = 0; const unsigned char *real_prefix; unsigned short flags = 0; int channels_size; if(diversity_kind != DIVERSITY_CHANNEL) channels_len = -1; channels_size = channels_len >= 0 ? channels_len + 2 : 0; if(!if_up(ifp)) return; add_metric = output_filter(id, prefix, plen, ifp->ifindex); if(add_metric >= INFINITY) return; metric = MIN(metric + add_metric, INFINITY); /* Worst case */ ensure_space(ifp, 20 + 12 + 28); v4 = plen >= 96 && v4mapped(prefix); if(v4) { if(!babel_ifp->ipv4) return; if(!babel_ifp->have_buffered_nh || memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) { start_message(ifp, MESSAGE_NH, 6); accumulate_byte(ifp, 1); accumulate_byte(ifp, 0); accumulate_bytes(ifp, babel_ifp->ipv4, 4); end_message(ifp, MESSAGE_NH, 6); memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4); babel_ifp->have_buffered_nh = 1; } real_prefix = prefix + 12; real_plen = plen - 96; } else { if(babel_ifp->have_buffered_prefix) { while(omit < plen / 8 && babel_ifp->buffered_prefix[omit] == prefix[omit]) omit++; } if(!babel_ifp->have_buffered_prefix || plen >= 48) flags |= 0x80; real_prefix = prefix; real_plen = plen; } if(!babel_ifp->have_buffered_id || memcmp(id, babel_ifp->buffered_id, 8) != 0) { if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) { flags |= 0x40; } else { start_message(ifp, MESSAGE_ROUTER_ID, 10); accumulate_short(ifp, 0); accumulate_bytes(ifp, id, 8); end_message(ifp, MESSAGE_ROUTER_ID, 10); } memcpy(babel_ifp->buffered_id, id, 16); babel_ifp->have_buffered_id = 1; } start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); accumulate_byte(ifp, v4 ? 1 : 2); accumulate_byte(ifp, flags); accumulate_byte(ifp, real_plen); accumulate_byte(ifp, omit); accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10); accumulate_short(ifp, seqno); accumulate_short(ifp, metric); accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); /* Note that an empty channels TLV is different from no such TLV. */ if(channels_len >= 0) { accumulate_byte(ifp, 2); accumulate_byte(ifp, channels_len); accumulate_bytes(ifp, channels, channels_len); } end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); if(flags & 0x80) { memcpy(babel_ifp->buffered_prefix, prefix, 16); babel_ifp->have_buffered_prefix = 1; } } static int compare_buffered_updates(const void *av, const void *bv) { const struct buffered_update *a = av, *b = bv; int rc, v4a, v4b, ma, mb; rc = memcmp(a->id, b->id, 8); if(rc != 0) return rc; v4a = (a->plen >= 96 && v4mapped(a->prefix)); v4b = (b->plen >= 96 && v4mapped(b->prefix)); if(v4a > v4b) return 1; else if(v4a < v4b) return -1; ma = (!v4a && a->plen == 128 && memcmp(a->prefix + 8, a->id, 8) == 0); mb = (!v4b && b->plen == 128 && memcmp(b->prefix + 8, b->id, 8) == 0); if(ma > mb) return -1; else if(mb > ma) return 1; if(a->plen < b->plen) return 1; else if(a->plen > b->plen) return -1; return memcmp(a->prefix, b->prefix, 16); } void flushupdates(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; struct xroute *xroute; struct babel_route *route; const unsigned char *last_prefix = NULL; unsigned char last_plen = 0xFF; int i; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) flushupdates(ifp_aux); return; } babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->num_buffered_updates > 0) { struct buffered_update *b = babel_ifp->buffered_updates; int n = babel_ifp->num_buffered_updates; babel_ifp->buffered_updates = NULL; babel_ifp->update_bufsize = 0; babel_ifp->num_buffered_updates = 0; if(!if_up(ifp)) goto done; debugf(BABEL_DEBUG_COMMON," (flushing %d buffered updates on %s (%d))", n, ifp->name, ifp->ifindex); /* In order to send fewer update messages, we want to send updates with the same router-id together, with IPv6 going out before IPv4. */ for(i = 0; i < n; i++) { route = find_installed_route(b[i].prefix, b[i].plen); if(route) memcpy(b[i].id, route->src->id, 8); else memcpy(b[i].id, myid, 8); } qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); for(i = 0; i < n; i++) { /* The same update may be scheduled multiple times before it is sent out. Since our buffer is now sorted, it is enough to compare with the previous update. */ if(last_prefix) { if(b[i].plen == last_plen && memcmp(b[i].prefix, last_prefix, 16) == 0) continue; } xroute = find_xroute(b[i].prefix, b[i].plen); route = find_installed_route(b[i].prefix, b[i].plen); if(xroute && (!route || xroute->metric <= kernel_metric)) { really_send_update(ifp, myid, xroute->prefix, xroute->plen, myseqno, xroute->metric, NULL, 0); last_prefix = xroute->prefix; last_plen = xroute->plen; } else if(route) { unsigned char channels[DIVERSITY_HOPS]; int chlen; struct interface *route_ifp = route->neigh->ifp; struct babel_interface *babel_route_ifp = NULL; unsigned short metric; unsigned short seqno; seqno = route->seqno; metric = route_interferes(route, ifp) ? route_metric(route) : route_metric_noninterfering(route); if(metric < INFINITY) satisfy_request(route->src->prefix, route->src->plen, seqno, route->src->id, ifp); if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && route->neigh->ifp == ifp) continue; babel_route_ifp = babel_get_if_nfo(route_ifp); if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) { memcpy(channels, route->channels, DIVERSITY_HOPS); } else { if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN) channels[0] = BABEL_IF_CHANNEL_INTERFERING; else { assert(babel_route_ifp->channel > 0 && babel_route_ifp->channel <= 255); channels[0] = babel_route_ifp->channel; } memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1); } chlen = channels_len(channels); really_send_update(ifp, route->src->id, route->src->prefix, route->src->plen, seqno, metric, channels, chlen); update_source(route->src, seqno, metric); last_prefix = route->src->prefix; last_plen = route->src->plen; } else { /* There's no route for this prefix. This can happen shortly after an xroute has been retracted, so send a retraction. */ really_send_update(ifp, myid, b[i].prefix, b[i].plen, myseqno, INFINITY, NULL, -1); } } schedule_flush_now(ifp); done: free(b); } babel_ifp->update_flush_timeout.tv_sec = 0; babel_ifp->update_flush_timeout.tv_usec = 0; } static void schedule_update_flush(struct interface *ifp, int urgent) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned msecs; msecs = update_jitter(babel_ifp, urgent); if(babel_ifp->update_flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs) return; set_timeout(&babel_ifp->update_flush_timeout, msecs); } static void buffer_update(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->num_buffered_updates > 0 && babel_ifp->num_buffered_updates >= babel_ifp->update_bufsize) flushupdates(ifp); if(babel_ifp->update_bufsize == 0) { int n; assert(babel_ifp->buffered_updates == NULL); /* Allocate enough space to hold a full update. Since the number of installed routes will grow over time, make sure we have enough space to send a full-ish frame. */ n = installed_routes_estimate() + xroutes_estimate() + 4; n = MAX(n, babel_ifp->bufsize / 16); again: babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); if(babel_ifp->buffered_updates == NULL) { zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); if(n > 4) { /* Try again with a tiny buffer. */ n = 4; goto again; } return; } babel_ifp->update_bufsize = n; babel_ifp->num_buffered_updates = 0; } memcpy(babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].prefix, prefix, 16); babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].plen = plen; babel_ifp->num_buffered_updates++; } static void buffer_update_callback(struct babel_route *route, void *closure) { buffer_update((struct interface*)closure, route->src->prefix, route->src->plen); } void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen) { babel_interface_nfo *babel_ifp = NULL; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; struct babel_route *route; FOR_ALL_INTERFACES(ifp_aux, linklist_node) send_update(ifp_aux, urgent, prefix, plen); if(prefix) { /* Since flushupdates only deals with non-wildcard interfaces, we need to do this now. */ route = find_installed_route(prefix, plen); if(route && route_metric(route) < INFINITY) satisfy_request(prefix, plen, route->src->seqno, route->src->id, NULL); } return; } if(!if_up(ifp)) return; babel_ifp = babel_get_if_nfo(ifp); if(prefix) { debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", ifp->name, format_prefix(prefix, plen)); buffer_update(ifp, prefix, plen); } else { send_self_update(ifp); debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); for_all_installed_routes(buffer_update_callback, ifp); set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); babel_ifp->last_update_time = babel_now.tv_sec; } schedule_update_flush(ifp, urgent); } void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { assert(prefix != NULL); send_update(ifp, 1, prefix, plen); record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, resend_delay); } void send_wildcard_retraction(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) send_wildcard_retraction(ifp_aux); return; } if(!if_up(ifp)) return; babel_ifp = babel_get_if_nfo(ifp); start_message(ifp, MESSAGE_UPDATE, 10); accumulate_byte(ifp, 0); accumulate_byte(ifp, 0x40); accumulate_byte(ifp, 0); accumulate_byte(ifp, 0); accumulate_short(ifp, 0xFFFF); accumulate_short(ifp, myseqno); accumulate_short(ifp, 0xFFFF); end_message(ifp, MESSAGE_UPDATE, 10); babel_ifp->have_buffered_id = 0; } void update_myseqno() { myseqno = seqno_plus(myseqno, 1); seqno_time = babel_now; } static void send_xroute_update_callback(struct xroute *xroute, void *closure) { struct interface *ifp = (struct interface*)closure; send_update(ifp, 0, xroute->prefix, xroute->plen); } void send_self_update(struct interface *ifp) { if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(!if_up(ifp_aux)) continue; send_self_update(ifp_aux); } return; } debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); for_all_xroutes(send_xroute_update_callback, ifp); } void send_ihu(struct neighbour *neigh, struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; int rxcost, interval; int ll; if(neigh == NULL && ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(if_up(ifp_aux)) continue; send_ihu(NULL, ifp_aux); } return; } if(neigh == NULL) { struct neighbour *ngh; FOR_ALL_NEIGHBOURS(ngh) { if(ngh->ifp == ifp) send_ihu(ngh, ifp); } return; } if(ifp && neigh->ifp != ifp) return; ifp = neigh->ifp; babel_ifp = babel_get_if_nfo(ifp); if(!if_up(ifp)) return; rxcost = neighbour_rxcost(neigh); interval = (babel_ifp->hello_interval * 3 + 9) / 10; /* Conceptually, an IHU is a unicast message. We usually send them as multicast, since this allows aggregation into a single packet and avoids an ARP exchange. If we already have a unicast message queued for this neighbour, however, we might as well piggyback the IHU. */ debugf(BABEL_DEBUG_COMMON,"Sending %sihu %d on %s to %s.", unicast_neighbour == neigh ? "unicast " : "", rxcost, neigh->ifp->name, format_address(neigh->address)); ll = linklocal(neigh->address); if(unicast_neighbour != neigh) { start_message(ifp, MESSAGE_IHU, ll ? 14 : 22); accumulate_byte(ifp, ll ? 3 : 2); accumulate_byte(ifp, 0); accumulate_short(ifp, rxcost); accumulate_short(ifp, interval); if(ll) accumulate_bytes(ifp, neigh->address + 8, 8); else accumulate_bytes(ifp, neigh->address, 16); end_message(ifp, MESSAGE_IHU, ll ? 14 : 22); } else { int rc; rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); if(rc < 0) return; accumulate_unicast_byte(neigh, ll ? 3 : 2); accumulate_unicast_byte(neigh, 0); accumulate_unicast_short(neigh, rxcost); accumulate_unicast_short(neigh, interval); if(ll) accumulate_unicast_bytes(neigh, neigh->address + 8, 8); else accumulate_unicast_bytes(neigh, neigh->address, 16); end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); } } /* Send IHUs to all marginal neighbours */ void send_marginal_ihu(struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { if(ifp && neigh->ifp != ifp) continue; if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) send_ihu(neigh, ifp); } } void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { int v4, len; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(if_up(ifp_aux)) continue; send_request(ifp_aux, prefix, plen); } return; } /* make sure any buffered updates go out before this request. */ flushupdates(ifp); if(!if_up(ifp)) return; debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", ifp->name, prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); len = !prefix ? 2 : v4 ? 6 : 18; start_message(ifp, MESSAGE_REQUEST, len); accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2); accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen); if(prefix) { if(v4) accumulate_bytes(ifp, prefix + 12, 4); else accumulate_bytes(ifp, prefix, 16); } end_message(ifp, MESSAGE_REQUEST, len); } void send_unicast_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen) { int rc, v4, len; /* make sure any buffered updates go out before this request. */ flushupdates(neigh->ifp); debugf(BABEL_DEBUG_COMMON,"sending unicast request to %s for %s.", format_address(neigh->address), prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); len = !prefix ? 2 : v4 ? 6 : 18; rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); if(rc < 0) return; accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? 1 : 2); accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen); if(prefix) { if(v4) accumulate_unicast_bytes(neigh, prefix + 12, 4); else accumulate_unicast_bytes(neigh, prefix, 16); } end_unicast_message(neigh, MESSAGE_REQUEST, len); } void send_multihop_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count) { int v4, pb, len; /* Make sure any buffered updates go out before this request. */ flushupdates(ifp); if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(!if_up(ifp_aux)) continue; send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count); } return; } if(!if_up(ifp)) return; debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", hop_count, ifp->name, format_prefix(prefix, plen)); v4 = plen >= 96 && v4mapped(prefix); pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; len = 6 + 8 + pb; start_message(ifp, MESSAGE_MH_REQUEST, len); accumulate_byte(ifp, v4 ? 1 : 2); accumulate_byte(ifp, v4 ? plen - 96 : plen); accumulate_short(ifp, seqno); accumulate_byte(ifp, hop_count); accumulate_byte(ifp, 0); accumulate_bytes(ifp, id, 8); if(prefix) { if(v4) accumulate_bytes(ifp, prefix + 12, pb); else accumulate_bytes(ifp, prefix, pb); } end_message(ifp, MESSAGE_MH_REQUEST, len); } void send_unicast_multihop_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count) { int rc, v4, pb, len; /* Make sure any buffered updates go out before this request. */ flushupdates(neigh->ifp); debugf(BABEL_DEBUG_COMMON,"Sending multi-hop request to %s for %s (%d hops).", format_address(neigh->address), format_prefix(prefix, plen), hop_count); v4 = plen >= 96 && v4mapped(prefix); pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; len = 6 + 8 + pb; rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len); if(rc < 0) return; accumulate_unicast_byte(neigh, v4 ? 1 : 2); accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen); accumulate_unicast_short(neigh, seqno); accumulate_unicast_byte(neigh, hop_count); accumulate_unicast_byte(neigh, 0); accumulate_unicast_bytes(neigh, id, 8); if(prefix) { if(v4) accumulate_unicast_bytes(neigh, prefix + 12, pb); else accumulate_unicast_bytes(neigh, prefix, pb); } end_unicast_message(neigh, MESSAGE_MH_REQUEST, len); } void send_request_resend(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned char *id) { if(neigh) send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); else send_multihop_request(NULL, prefix, plen, seqno, id, 127); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, neigh ? neigh->ifp : NULL, resend_delay); } void handle_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned char hop_count, unsigned short seqno, const unsigned char *id) { struct xroute *xroute; struct babel_route *route; struct neighbour *successor = NULL; xroute = find_xroute(prefix, plen); route = find_installed_route(prefix, plen); if(xroute && (!route || xroute->metric <= kernel_metric)) { if(hop_count > 0 && memcmp(id, myid, 8) == 0) { if(seqno_compare(seqno, myseqno) > 0) { if(seqno_minus(seqno, myseqno) > 100) { /* Hopelessly out-of-date request */ return; } update_myseqno(); } } send_update(neigh->ifp, 1, prefix, plen); return; } if(route && (memcmp(id, route->src->id, 8) != 0 || seqno_compare(seqno, route->seqno) <= 0)) { send_update(neigh->ifp, 1, prefix, plen); return; } if(hop_count <= 1) return; if(route && memcmp(id, route->src->id, 8) == 0 && seqno_minus(seqno, route->seqno) > 100) { /* Hopelessly out-of-date */ return; } if(request_redundant(neigh->ifp, prefix, plen, seqno, id)) return; /* Let's try to forward this request. */ if(route && route_metric(route) < INFINITY) successor = route->neigh; if(!successor || successor == neigh) { /* We were about to forward a request to its requestor. Try to find a different neighbour to forward the request to. */ struct babel_route *other_route; other_route = find_best_route(prefix, plen, 0, neigh); if(other_route && route_metric(other_route) < INFINITY) successor = other_route->neigh; } if(!successor || successor == neigh) /* Give up */ return; send_unicast_multihop_request(successor, prefix, plen, seqno, id, hop_count - 1); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, neigh->ifp, 0); } quagga-0.99.22.4/babeld/message.h0000644000175000017500000001106412177450262013243 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #ifndef BABEL_MESSAGE_H #define BABEL_MESSAGE_H #include "babel_interface.h" #define MAX_BUFFERED_UPDATES 200 #define BUCKET_TOKENS_MAX 200 #define BUCKET_TOKENS_PER_SEC 40 #define MESSAGE_PAD1 0 #define MESSAGE_PADN 1 #define MESSAGE_ACK_REQ 2 #define MESSAGE_ACK 3 #define MESSAGE_HELLO 4 #define MESSAGE_IHU 5 #define MESSAGE_ROUTER_ID 6 #define MESSAGE_NH 7 #define MESSAGE_UPDATE 8 #define MESSAGE_REQUEST 9 #define MESSAGE_MH_REQUEST 10 extern unsigned short myseqno; extern struct timeval seqno_time; extern int broadcast_ihu; extern int split_horizon; extern unsigned char packet_header[4]; extern struct neighbour *unicast_neighbour; extern struct timeval unicast_flush_timeout; void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen); void flushbuf(struct interface *ifp); void flushupdates(struct interface *ifp); void send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval); void send_hello_noupdate(struct interface *ifp, unsigned interval); void send_hello(struct interface *ifp); void flush_unicast(int dofree); void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen); void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen); void send_wildcard_retraction(struct interface *ifp); void update_myseqno(void); void send_self_update(struct interface *ifp); void send_ihu(struct neighbour *neigh, struct interface *ifp); void send_marginal_ihu(struct interface *ifp); void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen); void send_unicast_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen); void send_multihop_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count); void send_unicast_multihop_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count); void send_request_resend(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned char *id); void handle_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned char hop_count, unsigned short seqno, const unsigned char *id); #endif quagga-0.99.22.4/babeld/neighbour.c0000644000175000017500000002445112177450262013600 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #include #include #include #include #include #include #include "if.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "babel_interface.h" #include "neighbour.h" #include "source.h" #include "route.h" #include "message.h" #include "resend.h" struct neighbour *neighs = NULL; static struct neighbour * find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { if(memcmp(address, neigh->address, 16) == 0 && neigh->ifp == ifp) return neigh; } return NULL; } void flush_neighbour(struct neighbour *neigh) { flush_neighbour_routes(neigh); if(unicast_neighbour == neigh) flush_unicast(1); flush_resends(neigh); if(neighs == neigh) { neighs = neigh->next; } else { struct neighbour *previous = neighs; while(previous->next != neigh) previous = previous->next; previous->next = neigh->next; } free(neigh); } struct neighbour * find_neighbour(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; const struct timeval zero = {0, 0}; neigh = find_neighbour_nocreate(address, ifp); if(neigh) return neigh; debugf(BABEL_DEBUG_COMMON,"Creating neighbour %s on %s.", format_address(address), ifp->name); neigh = malloc(sizeof(struct neighbour)); if(neigh == NULL) { zlog_err("malloc(neighbour): %s", safe_strerror(errno)); return NULL; } neigh->hello_seqno = -1; memcpy(neigh->address, address, 16); neigh->reach = 0; neigh->txcost = INFINITY; neigh->ihu_time = babel_now; neigh->hello_time = zero; neigh->hello_interval = 0; neigh->ihu_interval = 0; neigh->ifp = ifp; neigh->next = neighs; neighs = neigh; send_hello(ifp); return neigh; } /* Recompute a neighbour's rxcost. Return true if anything changed. This does not call local_notify_neighbour, see update_neighbour_metric. */ int update_neighbour(struct neighbour *neigh, int hello, int hello_interval) { int missed_hellos; int rc = 0; if(hello < 0) { if(neigh->hello_interval <= 0) return rc; missed_hellos = ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) - neigh->hello_interval * 7) / (neigh->hello_interval * 10); if(missed_hellos <= 0) return rc; timeval_add_msec(&neigh->hello_time, &neigh->hello_time, missed_hellos * neigh->hello_interval * 10); } else { if(neigh->hello_seqno >= 0 && neigh->reach > 0) { missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1; if(missed_hellos < -8) { /* Probably a neighbour that rebooted and lost its seqno. Reboot the universe. */ neigh->reach = 0; missed_hellos = 0; rc = 1; } else if(missed_hellos < 0) { if(hello_interval > neigh->hello_interval) { /* This neighbour has increased its hello interval, and we didn't notice. */ neigh->reach <<= -missed_hellos; missed_hellos = 0; } else { /* Late hello. Probably due to the link layer buffering packets during a link outage. Ignore it, but reset the expected seqno. */ neigh->hello_seqno = hello; hello = -1; missed_hellos = 0; } rc = 1; } } else { missed_hellos = 0; } neigh->hello_time = babel_now; neigh->hello_interval = hello_interval; } if(missed_hellos > 0) { neigh->reach >>= missed_hellos; neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos); missed_hellos = 0; rc = 1; } if(hello >= 0) { neigh->hello_seqno = hello; neigh->reach >>= 1; neigh->reach |= 0x8000; if((neigh->reach & 0xFC00) != 0xFC00) rc = 1; } /* Make sure to give neighbours some feedback early after association */ if((neigh->reach & 0xBF00) == 0x8000) { /* A new neighbour */ send_hello(neigh->ifp); } else { /* Don't send hellos, in order to avoid a positive feedback loop. */ int a = (neigh->reach & 0xC000); int b = (neigh->reach & 0x3000); if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { /* Reachability is either 1100 or 0011 */ send_self_update(neigh->ifp); } } if((neigh->reach & 0xFC00) == 0xC000) { /* This is a newish neighbour, let's request a full route dump. We ought to avoid this when the network is dense */ send_unicast_request(neigh, NULL, 0); send_ihu(neigh, NULL); } return rc; } static int reset_txcost(struct neighbour *neigh) { unsigned delay; delay = timeval_minus_msec(&babel_now, &neigh->ihu_time); if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10U * 3U) return 0; /* If we're losing a lot of packets, we probably lost an IHU too */ if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || (neigh->ihu_interval > 0 && delay >= neigh->ihu_interval * 10U * 10U)) { neigh->txcost = INFINITY; neigh->ihu_time = babel_now; return 1; } return 0; } unsigned neighbour_txcost(struct neighbour *neigh) { return neigh->txcost; } unsigned check_neighbours() { struct neighbour *neigh; int changed, rc; unsigned msecs = 50000; debugf(BABEL_DEBUG_COMMON,"Checking neighbours."); neigh = neighs; while(neigh) { changed = update_neighbour(neigh, -1, 0); if(neigh->reach == 0 || neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */ timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) { struct neighbour *old = neigh; neigh = neigh->next; flush_neighbour(old); continue; } rc = reset_txcost(neigh); changed = changed || rc; update_neighbour_metric(neigh, changed); if(neigh->hello_interval > 0) msecs = MIN(msecs, neigh->hello_interval * 10U); if(neigh->ihu_interval > 0) msecs = MIN(msecs, neigh->ihu_interval * 10U); neigh = neigh->next; } return msecs; } unsigned neighbour_rxcost(struct neighbour *neigh) { unsigned delay; unsigned short reach = neigh->reach; delay = timeval_minus_msec(&babel_now, &neigh->hello_time); if((reach & 0xFFF0) == 0 || delay >= 180000) { return INFINITY; } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { int sreach = ((reach & 0x8000) >> 2) + ((reach & 0x4000) >> 1) + (reach & 0x3FFF); /* 0 <= sreach <= 0x7FFF */ int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); /* cost >= interface->cost */ if(delay >= 40000) cost = (cost * (delay - 20000) + 10000) / 20000; return MIN(cost, INFINITY); } else { /* To lose one hello is a misfortune, to lose two is carelessness. */ if((reach & 0xC000) == 0xC000) return babel_get_if_nfo(neigh->ifp)->cost; else if((reach & 0xC000) == 0) return INFINITY; else if((reach & 0x2000)) return babel_get_if_nfo(neigh->ifp)->cost; else return INFINITY; } } unsigned neighbour_cost(struct neighbour *neigh) { unsigned a, b; if(!if_up(neigh->ifp)) return INFINITY; a = neighbour_txcost(neigh); if(a >= INFINITY) return INFINITY; b = neighbour_rxcost(neigh); if(b >= INFINITY) return INFINITY; if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) || (a < 256 && b < 256)) { return a; } else { /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected probabilities of a packet getting through in the direct and reverse directions. */ a = MAX(a, 256); b = MAX(b, 256); /* 1/(alpha * beta), which is just plain ETX. */ /* Since a and b are capped to 16 bits, overflow is impossible. */ return (a * b + 128) >> 8; } } quagga-0.99.22.4/babeld/neighbour.h0000644000175000017500000000551012177450262013600 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ struct neighbour { struct neighbour *next; /* This is -1 when unknown, so don't make it unsigned */ int hello_seqno; unsigned char address[16]; unsigned short reach; unsigned short txcost; struct timeval hello_time; struct timeval ihu_time; unsigned short hello_interval; /* in centiseconds */ unsigned short ihu_interval; /* in centiseconds */ struct interface *ifp; }; extern struct neighbour *neighs; #define FOR_ALL_NEIGHBOURS(_neigh) \ for(_neigh = neighs; _neigh; _neigh = _neigh->next) int neighbour_valid(struct neighbour *neigh); void flush_neighbour(struct neighbour *neigh); struct neighbour *find_neighbour(const unsigned char *address, struct interface *ifp); int update_neighbour(struct neighbour *neigh, int hello, int hello_interval); unsigned check_neighbours(void); unsigned neighbour_txcost(struct neighbour *neigh); unsigned neighbour_rxcost(struct neighbour *neigh); unsigned neighbour_cost(struct neighbour *neigh); quagga-0.99.22.4/babeld/net.c0000644000175000017500000001361312177450262012402 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #include #include #include #include #include #include #include #include #include #include #include "babeld.h" #include "util.h" #include "net.h" int babel_socket(int port) { struct sockaddr_in6 sin6; int s, rc; int saved_errno; int one = 1, zero = 0; const int ds = 0xc0; /* CS6 - Network Control */ s = socket(PF_INET6, SOCK_DGRAM, 0); if(s < 0) return -1; rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); if(rc < 0) goto fail; rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &one, sizeof(one)); if(rc < 0) goto fail; #ifdef IPV6_TCLASS rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)); #else rc = -1; errno = ENOSYS; #endif if(rc < 0) perror("Couldn't set traffic class"); rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFD, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); if(rc < 0) goto fail; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) goto fail; return s; fail: saved_errno = errno; close(s); errno = saved_errno; return -1; } int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen) { struct iovec iovec; struct msghdr msg; int rc; memset(&msg, 0, sizeof(msg)); iovec.iov_base = buf; iovec.iov_len = buflen; msg.msg_name = sin; msg.msg_namelen = slen; msg.msg_iov = &iovec; msg.msg_iovlen = 1; rc = recvmsg(s, &msg, 0); return rc; } int babel_send(int s, void *buf1, int buflen1, void *buf2, int buflen2, struct sockaddr *sin, int slen) { struct iovec iovec[2]; struct msghdr msg; int rc; iovec[0].iov_base = buf1; iovec[0].iov_len = buflen1; iovec[1].iov_base = buf2; iovec[1].iov_len = buflen2; memset(&msg, 0, sizeof(msg)); msg.msg_name = (struct sockaddr*)sin; msg.msg_namelen = slen; msg.msg_iov = iovec; msg.msg_iovlen = 2; again: rc = sendmsg(s, &msg, 0); if(rc < 0) { if(errno == EINTR) goto again; else if(errno == EAGAIN) { int rc2; rc2 = wait_for_fd(1, s, 5); if(rc2 > 0) goto again; errno = EAGAIN; } } return rc; } int tcp_server_socket(int port, int local) { struct sockaddr_in6 sin6; int s, rc, saved_errno; int one = 1; s = socket(PF_INET6, SOCK_STREAM, 0); if(s < 0) return -1; rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFD, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); if(rc < 0) goto fail; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); if(local) { rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr); if(rc < 0) goto fail; } rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) goto fail; rc = listen(s, 2); if(rc < 0) goto fail; return s; fail: saved_errno = errno; close(s); errno = saved_errno; return -1; } quagga-0.99.22.4/babeld/net.h0000644000175000017500000000414512177450262012407 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ int babel_socket(int port); int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen); int babel_send(int s, void *buf1, int buflen1, void *buf2, int buflen2, struct sockaddr *sin, int slen); int tcp_server_socket(int port, int local); quagga-0.99.22.4/babeld/resend.c0000644000175000017500000002261612177450262013077 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #include #include #include #include #include #include "if.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "neighbour.h" #include "resend.h" #include "message.h" #include "babel_interface.h" struct timeval resend_time = {0, 0}; struct resend *to_resend = NULL; static int resend_match(struct resend *resend, int kind, const unsigned char *prefix, unsigned char plen) { return (resend->kind == kind && resend->plen == plen && memcmp(resend->prefix, prefix, 16) == 0); } /* This is called by neigh.c when a neighbour is flushed */ void flush_resends(struct neighbour *neigh) { /* Nothing for now */ } static struct resend * find_resend(int kind, const unsigned char *prefix, unsigned char plen, struct resend **previous_return) { struct resend *current, *previous; previous = NULL; current = to_resend; while(current) { if(resend_match(current, kind, prefix, plen)) { if(previous_return) *previous_return = previous; return current; } previous = current; current = current->next; } return NULL; } struct resend * find_request(const unsigned char *prefix, unsigned char plen, struct resend **previous_return) { return find_resend(RESEND_REQUEST, prefix, plen, previous_return); } int record_resend(int kind, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp, int delay) { struct resend *resend; unsigned int ifindex = ifp ? ifp->ifindex : 0; if((kind == RESEND_REQUEST && input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) || (kind == RESEND_UPDATE && output_filter(NULL, prefix, plen, ifindex) >= INFINITY)) return 0; if(delay >= 0xFFFF) delay = 0xFFFF; resend = find_resend(kind, prefix, plen, NULL); if(resend) { if(resend->delay && delay) resend->delay = MIN(resend->delay, delay); else if(delay) resend->delay = delay; resend->time = babel_now; resend->max = RESEND_MAX; if(id && memcmp(resend->id, id, 8) == 0 && seqno_compare(resend->seqno, seqno) > 0) { return 0; } if(id) memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); resend->seqno = seqno; if(resend->ifp != ifp) resend->ifp = NULL; } else { resend = malloc(sizeof(struct resend)); if(resend == NULL) return -1; resend->kind = kind; resend->max = RESEND_MAX; resend->delay = delay; memcpy(resend->prefix, prefix, 16); resend->plen = plen; resend->seqno = seqno; if(id) memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); resend->ifp = ifp; resend->time = babel_now; resend->next = to_resend; to_resend = resend; } if(resend->delay) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); timeval_min(&resend_time, &timeout); } return 1; } static int resend_expired(struct resend *resend) { switch(resend->kind) { case RESEND_REQUEST: return timeval_minus_msec(&babel_now, &resend->time) >= REQUEST_TIMEOUT; default: return resend->max <= 0; } } int unsatisfied_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) != 0 || seqno_compare(request->seqno, seqno) <= 0) return 1; return 0; } /* Determine whether a given request should be forwarded. */ int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) == 0 && seqno_compare(request->seqno, seqno) > 0) return 0; if(request->ifp != NULL && request->ifp != ifp) return 0; if(request->max > 0) /* Will be resent. */ return 1; if(timeval_minus_msec(&babel_now, &request->time) < (ifp ? MIN(babel_get_if_nfo(ifp)->hello_interval, 1000) : 1000)) /* Fairly recent. */ return 1; return 0; } int satisfy_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp) { struct resend *request, *previous; request = find_request(prefix, plen, &previous); if(request == NULL) return 0; if(ifp != NULL && request->ifp != ifp) return 0; if(memcmp(request->id, id, 8) != 0 || seqno_compare(request->seqno, seqno) <= 0) { /* We cannot remove the request, as we may be walking the list right now. Mark it as expired, so that expire_resend will remove it. */ request->max = 0; request->time.tv_sec = 0; recompute_resend_time(); return 1; } return 0; } void expire_resend() { struct resend *current, *previous; int recompute = 0; previous = NULL; current = to_resend; while(current) { if(resend_expired(current)) { if(previous == NULL) { to_resend = current->next; free(current); current = to_resend; } else { previous->next = current->next; free(current); current = previous->next; } recompute = 1; } else { previous = current; current = current->next; } } if(recompute) recompute_resend_time(); } void recompute_resend_time() { struct resend *request; struct timeval resend = {0, 0}; request = to_resend; while(request) { if(!resend_expired(request) && request->delay > 0 && request->max > 0) { struct timeval timeout; timeval_add_msec(&timeout, &request->time, request->delay); timeval_min(&resend, &timeout); } request = request->next; } resend_time = resend; } void do_resend() { struct resend *resend; resend = to_resend; while(resend) { if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); if(timeval_compare(&babel_now, &timeout) >= 0) { switch(resend->kind) { case RESEND_REQUEST: send_multihop_request(resend->ifp, resend->prefix, resend->plen, resend->seqno, resend->id, 127); break; case RESEND_UPDATE: send_update(resend->ifp, 1, resend->prefix, resend->plen); break; default: abort(); } resend->delay = MIN(0xFFFF, resend->delay * 2); resend->max--; } } resend = resend->next; } recompute_resend_time(); } quagga-0.99.22.4/babeld/resend.h0000644000175000017500000000626412177450262013105 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #define REQUEST_TIMEOUT 65000 #define RESEND_MAX 3 #define RESEND_REQUEST 1 #define RESEND_UPDATE 2 struct resend { unsigned char kind; unsigned char max; unsigned short delay; struct timeval time; unsigned char prefix[16]; unsigned char plen; unsigned short seqno; unsigned char id[8]; struct interface *ifp; struct resend *next; }; extern struct timeval resend_time; struct resend *find_request(const unsigned char *prefix, unsigned char plen, struct resend **previous_return); void flush_resends(struct neighbour *neigh); int record_resend(int kind, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp, int delay); int unsatisfied_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id); int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id); int satisfy_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp); void expire_resend(void); void recompute_resend_time(void); void do_resend(void); quagga-0.99.22.4/babeld/route.c0000644000175000017500000007032512177450262012755 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include #include "if.h" #include "babeld.h" #include "util.h" #include "kernel.h" #include "babel_interface.h" #include "source.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #include "message.h" #include "resend.h" static void consider_route(struct babel_route *route); struct babel_route **routes = NULL; static int route_slots = 0, max_route_slots = 0; int kernel_metric = 0; int allow_duplicates = -1; int diversity_kind = DIVERSITY_NONE; int diversity_factor = 256; /* in units of 1/256 */ int keep_unfeasible = 0; /* We maintain a list of "slots", ordered by prefix. Every slot contains a linked list of the routes to this prefix, with the installed route, if any, at the head of the list. */ static int route_compare(const unsigned char *prefix, unsigned char plen, struct babel_route *route) { int i = memcmp(prefix, route->src->prefix, 16); if(i != 0) return i; if(plen < route->src->plen) return -1; else if(plen > route->src->plen) return 1; else return 0; } /* Performs binary search, returns -1 in case of failure. In the latter case, new_return is the place where to insert the new element. */ static int find_route_slot(const unsigned char *prefix, unsigned char plen, int *new_return) { int p, m, g, c; if(route_slots < 1) { if(new_return) *new_return = 0; return -1; } p = 0; g = route_slots - 1; do { m = (p + g) / 2; c = route_compare(prefix, plen, routes[m]); if(c == 0) return m; else if(c < 0) g = m - 1; else p = m + 1; } while(p <= g); if(new_return) *new_return = p; return -1; } struct babel_route * find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop) { struct babel_route *route; int i = find_route_slot(prefix, plen, NULL); if(i < 0) return NULL; route = routes[i]; while(route) { if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0) return route; route = route->next; } return NULL; } struct babel_route * find_installed_route(const unsigned char *prefix, unsigned char plen) { int i = find_route_slot(prefix, plen, NULL); if(i >= 0 && routes[i]->installed) return routes[i]; return NULL; } /* Returns an overestimate of the number of installed routes. */ int installed_routes_estimate(void) { return route_slots; } static int resize_route_table(int new_slots) { struct babel_route **new_routes; assert(new_slots >= route_slots); if(new_slots == 0) { new_routes = NULL; free(routes); } else { new_routes = realloc(routes, new_slots * sizeof(struct babel_route*)); if(new_routes == NULL) return -1; } max_route_slots = new_slots; routes = new_routes; return 1; } /* Insert a route into the table. If successful, retains the route. On failure, caller must free the route. */ static struct babel_route * insert_route(struct babel_route *route) { int i, n; assert(!route->installed); i = find_route_slot(route->src->prefix, route->src->plen, &n); if(i < 0) { if(route_slots >= max_route_slots) resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots); if(route_slots >= max_route_slots) return NULL; route->next = NULL; if(n < route_slots) memmove(routes + n + 1, routes + n, (route_slots - n) * sizeof(struct babel_route*)); route_slots++; routes[n] = route; } else { struct babel_route *r; r = routes[i]; while(r->next) r = r->next; r->next = route; route->next = NULL; } return route; } void flush_route(struct babel_route *route) { int i; struct source *src; unsigned oldmetric; int lost = 0; oldmetric = route_metric(route); src = route->src; if(route->installed) { uninstall_route(route); lost = 1; } i = find_route_slot(route->src->prefix, route->src->plen, NULL); assert(i >= 0 && i < route_slots); if(route == routes[i]) { routes[i] = route->next; route->next = NULL; free(route); if(routes[i] == NULL) { if(i < route_slots - 1) memmove(routes + i, routes + i + 1, (route_slots - i - 1) * sizeof(struct babel_route*)); routes[route_slots - 1] = NULL; route_slots--; } if(route_slots == 0) resize_route_table(0); else if(max_route_slots > 8 && route_slots < max_route_slots / 4) resize_route_table(max_route_slots / 2); } else { struct babel_route *r = routes[i]; while(r->next != route) r = r->next; r->next = route->next; route->next = NULL; free(route); } if(lost) route_lost(src, oldmetric); release_source(src); } void flush_all_routes() { int i; /* Start from the end, to avoid shifting the table. */ i = route_slots - 1; while(i >= 0) { while(i < route_slots) { /* Uninstall first, to avoid calling route_lost. */ if(routes[i]->installed) uninstall_route(routes[0]); flush_route(routes[i]); } i--; } check_sources_released(); } void flush_neighbour_routes(struct neighbour *neigh) { int i; i = 0; while(i < route_slots) { struct babel_route *r; r = routes[i]; while(r) { if(r->neigh == neigh) { flush_route(r); goto again; } r = r->next; } i++; again: ; } } void flush_interface_routes(struct interface *ifp, int v4only) { int i; i = 0; while(i < route_slots) { struct babel_route *r; r = routes[i]; while(r) { if(r->neigh->ifp == ifp && (!v4only || v4mapped(r->nexthop))) { flush_route(r); goto again; } r = r->next; } i++; again: ; } } /* Iterate a function over all routes. */ void for_all_routes(void (*f)(struct babel_route*, void*), void *closure) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { (*f)(r, closure); r = r->next; } } } void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure) { int i; for(i = 0; i < route_slots; i++) { if(routes[i]->installed) (*f)(routes[i], closure); } } static int metric_to_kernel(int metric) { return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; } /* This is used to maintain the invariant that the installed route is at the head of the list. */ static void move_installed_route(struct babel_route *route, int i) { assert(i >= 0 && i < route_slots); assert(route->installed); if(route != routes[i]) { struct babel_route *r = routes[i]; while(r->next != route) r = r->next; r->next = route->next; route->next = routes[i]; routes[i] = route; } } void install_route(struct babel_route *route) { int i, rc; if(route->installed) return; if(!route_feasible(route)) zlog_err("WARNING: installing unfeasible route " "(this shouldn't happen)."); i = find_route_slot(route->src->prefix, route->src->plen, NULL); assert(i >= 0 && i < route_slots); if(routes[i] != route && routes[i]->installed) { fprintf(stderr, "WARNING: attempting to install duplicate route " "(this shouldn't happen)."); return; } rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, metric_to_kernel(route_metric(route)), NULL, 0, 0); if(rc < 0) { int save = errno; zlog_err("kernel_route(ADD): %s", safe_strerror(errno)); if(save != EEXIST) return; } route->installed = 1; move_installed_route(route, i); } void uninstall_route(struct babel_route *route) { int rc; if(!route->installed) return; rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, metric_to_kernel(route_metric(route)), NULL, 0, 0); if(rc < 0) zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno)); route->installed = 0; } /* This is equivalent to uninstall_route followed with install_route, but without the race condition. The destination of both routes must be the same. */ static void switch_routes(struct babel_route *old, struct babel_route *new) { int rc; if(!old) { install_route(new); return; } if(!old->installed) return; if(!route_feasible(new)) zlog_err("WARNING: switching to unfeasible route " "(this shouldn't happen)."); rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, old->nexthop, old->neigh->ifp->ifindex, metric_to_kernel(route_metric(old)), new->nexthop, new->neigh->ifp->ifindex, metric_to_kernel(route_metric(new))); if(rc < 0) { zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno)); return; } old->installed = 0; new->installed = 1; move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen, NULL)); } static void change_route_metric(struct babel_route *route, unsigned refmetric, unsigned cost, unsigned add) { int old, new; int newmetric = MIN(refmetric + cost + add, INFINITY); old = metric_to_kernel(route_metric(route)); new = metric_to_kernel(newmetric); if(route->installed && old != new) { int rc; rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, old, route->nexthop, route->neigh->ifp->ifindex, new); if(rc < 0) { zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno)); return; } } route->refmetric = refmetric; route->cost = cost; route->add_metric = add; } static void retract_route(struct babel_route *route) { change_route_metric(route, INFINITY, INFINITY, 0); } int route_feasible(struct babel_route *route) { return update_feasible(route->src, route->seqno, route->refmetric); } int route_old(struct babel_route *route) { return route->time < babel_now.tv_sec - route->hold_time * 7 / 8; } int route_expired(struct babel_route *route) { return route->time < babel_now.tv_sec - route->hold_time; } static int channels_interfere(int ch1, int ch2) { if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING || ch2 == BABEL_IF_CHANNEL_NONINTERFERING) return 0; if(ch1 == BABEL_IF_CHANNEL_INTERFERING || ch2 == BABEL_IF_CHANNEL_INTERFERING) return 1; return ch1 == ch2; } int route_interferes(struct babel_route *route, struct interface *ifp) { struct babel_interface *babel_ifp = NULL; switch(diversity_kind) { case DIVERSITY_NONE: return 1; case DIVERSITY_INTERFACE_1: return route->neigh->ifp == ifp; case DIVERSITY_CHANNEL_1: case DIVERSITY_CHANNEL: if(route->neigh->ifp == ifp) return 1; babel_ifp = babel_get_if_nfo(ifp); if(channels_interfere(babel_ifp->channel, babel_get_if_nfo(route->neigh->ifp)->channel)) return 1; if(diversity_kind == DIVERSITY_CHANNEL) { int i; for(i = 0; i < DIVERSITY_HOPS; i++) { if(route->channels[i] == 0) break; if(channels_interfere(babel_ifp->channel, route->channels[i])) return 1; } } return 0; default: fprintf(stderr, "Unknown kind of diversity.\n"); return 1; } } int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric) { if(src == NULL) return 1; if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) /* Never mind what is probably stale data */ return 1; if(refmetric >= INFINITY) /* Retractions are always feasible */ return 1; return (seqno_compare(seqno, src->seqno) > 0 || (src->seqno == seqno && refmetric < src->metric)); } /* This returns the feasible route with the smallest metric. */ struct babel_route * find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude) { struct babel_route *route = NULL, *r = NULL; int i = find_route_slot(prefix, plen, NULL); if(i < 0) return NULL; route = routes[i]; r = route->next; while(r) { if(!route_expired(r) && (!feasible || route_feasible(r)) && (!exclude || r->neigh != exclude) && (route_metric(r) < route_metric(route))) route = r; r = r->next; } return route; } void update_route_metric(struct babel_route *route) { int oldmetric = route_metric(route); if(route_expired(route)) { if(route->refmetric < INFINITY) { route->seqno = seqno_plus(route->src->seqno, 1); retract_route(route); if(oldmetric < INFINITY) route_changed(route, route->src, oldmetric); } } else { struct neighbour *neigh = route->neigh; int add_metric = input_filter(route->src->id, route->src->prefix, route->src->plen, neigh->address, neigh->ifp->ifindex); change_route_metric(route, route->refmetric, neighbour_cost(route->neigh), add_metric); if(route_metric(route) != oldmetric) route_changed(route, route->src, oldmetric); } } /* Called whenever a neighbour's cost changes, to update the metric of all routes through that neighbour. Calls local_notify_neighbour. */ void update_neighbour_metric(struct neighbour *neigh, int changed) { if(changed) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { if(r->neigh == neigh) update_route_metric(r); r = r->next; } } } } void update_interface_metric(struct interface *ifp) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { if(r->neigh->ifp == ifp) update_route_metric(r); r = r->next; } } } /* This is called whenever we receive an update. */ struct babel_route * update_route(const unsigned char *router_id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop, const unsigned char *channels, int channels_len) { struct babel_route *route; struct source *src; int metric, feasible; int add_metric; int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); if(memcmp(router_id, myid, 8) == 0) return NULL; if(martian_prefix(prefix, plen)) { zlog_err("Rejecting martian route to %s through %s.", format_prefix(prefix, plen), format_address(router_id)); return NULL; } add_metric = input_filter(router_id, prefix, plen, neigh->address, neigh->ifp->ifindex); if(add_metric >= INFINITY) return NULL; route = find_route(prefix, plen, neigh, nexthop); if(route && memcmp(route->src->id, router_id, 8) == 0) /* Avoid scanning the source table. */ src = route->src; else src = find_source(router_id, prefix, plen, 1, seqno); if(src == NULL) return NULL; feasible = update_feasible(src, seqno, refmetric); metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); if(route) { struct source *oldsrc; unsigned short oldmetric; int lost = 0; oldsrc = route->src; oldmetric = route_metric(route); /* If a successor switches sources, we must accept his update even if it makes a route unfeasible in order to break any routing loops in a timely manner. If the source remains the same, we ignore the update. */ if(!feasible && route->installed) { debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s " "(%s %d %d -> %s %d %d).", format_prefix(src->prefix, src->plen), format_address(route->src->id), route->seqno, route->refmetric, format_address(src->id), seqno, refmetric); if(src != route->src) { uninstall_route(route); lost = 1; } } route->src = retain_source(src); if((feasible || keep_unfeasible) && refmetric < INFINITY) route->time = babel_now.tv_sec; route->seqno = seqno; change_route_metric(route, refmetric, neighbour_cost(neigh), add_metric); route->hold_time = hold_time; route_changed(route, oldsrc, oldmetric); if(lost) route_lost(oldsrc, oldmetric); if(!feasible) send_unfeasible_request(neigh, route->installed && route_old(route), seqno, metric, src); release_source(oldsrc); } else { struct babel_route *new_route; if(refmetric >= INFINITY) /* Somebody's retracting a route we never saw. */ return NULL; if(!feasible) { send_unfeasible_request(neigh, 0, seqno, metric, src); if(!keep_unfeasible) return NULL; } route = malloc(sizeof(struct babel_route)); if(route == NULL) { perror("malloc(route)"); return NULL; } route->src = retain_source(src); route->refmetric = refmetric; route->cost = neighbour_cost(neigh); route->add_metric = add_metric; route->seqno = seqno; route->neigh = neigh; memcpy(route->nexthop, nexthop, 16); route->time = babel_now.tv_sec; route->hold_time = hold_time; route->installed = 0; memset(&route->channels, 0, sizeof(route->channels)); if(channels_len > 0) memcpy(&route->channels, channels, MIN(channels_len, DIVERSITY_HOPS)); route->next = NULL; new_route = insert_route(route); if(new_route == NULL) { fprintf(stderr, "Couldn't insert route.\n"); free(route); return NULL; } consider_route(route); } return route; } /* We just received an unfeasible update. If it's any good, send a request for a new seqno. */ void send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, struct source *src) { struct babel_route *route = find_installed_route(src->prefix, src->plen); if(seqno_minus(src->seqno, seqno) > 100) { /* Probably a source that lost its seqno. Let it time-out. */ return; } if(force || !route || route_metric(route) >= metric + 512) { send_unicast_multihop_request(neigh, src->prefix, src->plen, src->metric >= INFINITY ? src->seqno : seqno_plus(src->seqno, 1), src->id, 127); } } /* This takes a feasible route and decides whether to install it. */ static void consider_route(struct babel_route *route) { struct babel_route *installed; struct xroute *xroute; if(route->installed) return; if(!route_feasible(route)) return; xroute = find_xroute(route->src->prefix, route->src->plen); if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates)) return; installed = find_installed_route(route->src->prefix, route->src->plen); if(installed == NULL) goto install; if(route_metric(route) >= INFINITY) return; if(route_metric(installed) >= INFINITY) goto install; if(route_metric(installed) >= route_metric(route) + 64) goto install; return; install: switch_routes(installed, route); if(installed && route->installed) send_triggered_update(route, installed->src, route_metric(installed)); else send_update(NULL, 1, route->src->prefix, route->src->plen); return; } void retract_neighbour_routes(struct neighbour *neigh) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { if(r->neigh == neigh) { if(r->refmetric != INFINITY) { unsigned short oldmetric = route_metric(r); retract_route(r); if(oldmetric != INFINITY) route_changed(r, r->src, oldmetric); } } r = r->next; } i++; } } void send_triggered_update(struct babel_route *route, struct source *oldsrc, unsigned oldmetric) { unsigned newmetric, diff; /* 1 means send speedily, 2 means resend */ int urgent; if(!route->installed) return; newmetric = route_metric(route); diff = newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric; if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY)) /* Switching sources can cause transient routing loops. Retractions can cause blackholes. */ urgent = 2; else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512) /* Route getting significantly worse */ urgent = 1; else if(unsatisfied_request(route->src->prefix, route->src->plen, route->seqno, route->src->id)) /* Make sure that requests are satisfied speedily */ urgent = 1; else if(oldmetric >= INFINITY && newmetric < INFINITY) /* New route */ urgent = 0; else if(newmetric < oldmetric && diff < 1024) /* Route getting better. This may be a transient fluctuation, so don't advertise it to avoid making routes unfeasible later on. */ return; else if(diff < 384) /* Don't fret about trivialities */ return; else urgent = 0; if(urgent >= 2) send_update_resend(NULL, route->src->prefix, route->src->plen); else send_update(NULL, urgent, route->src->prefix, route->src->plen); if(oldmetric < INFINITY) { if(newmetric >= oldmetric + 512) { send_request_resend(NULL, route->src->prefix, route->src->plen, route->src->metric >= INFINITY ? route->src->seqno : seqno_plus(route->src->seqno, 1), route->src->id); } else if(newmetric >= oldmetric + 288) { send_request(NULL, route->src->prefix, route->src->plen); } } } /* A route has just changed. Decide whether to switch to a different route or send an update. */ void route_changed(struct babel_route *route, struct source *oldsrc, unsigned short oldmetric) { if(route->installed) { if(route_metric(route) > oldmetric) { struct babel_route *better_route; better_route = find_best_route(route->src->prefix, route->src->plen, 1, NULL); if(better_route && route_metric(better_route) <= route_metric(route) - 96) consider_route(better_route); } if(route->installed) /* We didn't change routes after all. */ send_triggered_update(route, oldsrc, oldmetric); } else { /* Reconsider routes even when their metric didn't decrease, they may not have been feasible before. */ consider_route(route); } } /* We just lost the installed route to a given destination. */ void route_lost(struct source *src, unsigned oldmetric) { struct babel_route *new_route; new_route = find_best_route(src->prefix, src->plen, 1, NULL); if(new_route) { consider_route(new_route); } else if(oldmetric < INFINITY) { /* Complain loudly. */ send_update_resend(NULL, src->prefix, src->plen); send_request_resend(NULL, src->prefix, src->plen, src->metric >= INFINITY ? src->seqno : seqno_plus(src->seqno, 1), src->id); } } /* This is called periodically to flush old routes. It will also send requests for routes that are about to expire. */ void expire_routes(void) { struct babel_route *r; int i; debugf(BABEL_DEBUG_COMMON,"Expiring old routes."); i = 0; while(i < route_slots) { r = routes[i]; while(r) { /* Protect against clock being stepped. */ if(r->time > babel_now.tv_sec || route_old(r)) { flush_route(r); goto again; } update_route_metric(r); if(r->installed && r->refmetric < INFINITY) { if(route_old(r)) /* Route about to expire, send a request. */ send_unicast_request(r->neigh, r->src->prefix, r->src->plen); } r = r->next; } i++; again: ; } } quagga-0.99.22.4/babeld/route.h0000644000175000017500000001316412177450262012760 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #ifndef BABEL_ROUTE_H #define BABEL_ROUTE_H #include "babel_interface.h" #include "source.h" #define DIVERSITY_NONE 0 #define DIVERSITY_INTERFACE_1 1 #define DIVERSITY_CHANNEL_1 2 #define DIVERSITY_CHANNEL 3 #define DIVERSITY_HOPS 8 struct babel_route { struct source *src; unsigned short refmetric; unsigned short cost; unsigned short add_metric; unsigned short seqno; struct neighbour *neigh; unsigned char nexthop[16]; time_t time; unsigned short hold_time; /* in seconds */ short installed; unsigned char channels[DIVERSITY_HOPS]; struct babel_route *next; }; extern struct babel_route **routes; extern int kernel_metric, allow_duplicates; extern int diversity_kind, diversity_factor; extern int keep_unfeasible; static inline int route_metric(const struct babel_route *route) { int m = (int)route->refmetric + route->cost + route->add_metric; return MIN(m, INFINITY); } static inline int route_metric_noninterfering(const struct babel_route *route) { int m = (int)route->refmetric + (diversity_factor * route->cost + 128) / 256 + route->add_metric; m = MAX(m, route->refmetric + 1); return MIN(m, INFINITY); } struct babel_route *find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop); struct babel_route *find_installed_route(const unsigned char *prefix, unsigned char plen); int installed_routes_estimate(void); void flush_route(struct babel_route *route); void flush_all_routes(void); void flush_neighbour_routes(struct neighbour *neigh); void flush_interface_routes(struct interface *ifp, int v4only); void for_all_routes(void (*f)(struct babel_route*, void*), void *closure); void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure); void install_route(struct babel_route *route); void uninstall_route(struct babel_route *route); void switch_route(struct babel_route *old, struct babel_route *new); int route_feasible(struct babel_route *route); int route_old(struct babel_route *route); int route_expired(struct babel_route *route); int route_interferes(struct babel_route *route, struct interface *ifp); int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric); struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude); struct babel_route *install_best_route(const unsigned char prefix[16], unsigned char plen); void update_neighbour_metric(struct neighbour *neigh, int change); void update_interface_metric(struct interface *ifp); void update_route_metric(struct babel_route *route); struct babel_route *update_route(const unsigned char *id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop, const unsigned char *channels, int channels_len); void retract_neighbour_routes(struct neighbour *neigh); void send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, struct source *src); void send_triggered_update(struct babel_route *route, struct source *oldsrc, unsigned oldmetric); void route_changed(struct babel_route *route, struct source *oldsrc, unsigned short oldmetric); void route_lost(struct source *src, unsigned oldmetric); void expire_routes(void); #endif quagga-0.99.22.4/babeld/source.c0000644000175000017500000001206212177450262013111 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #include #include #include #include #include "babel_main.h" #include "babeld.h" #include "util.h" #include "source.h" #include "babel_interface.h" #include "route.h" struct source *srcs = NULL; struct source* find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, int create, unsigned short seqno) { struct source *src; for(src = srcs; src; src = src->next) { /* This should really be a hash table. For now, check the last byte first. */ if(src->id[7] != id[7]) continue; if(memcmp(src->id, id, 8) != 0) continue; if(src->plen != plen) continue; if(memcmp(src->prefix, p, 16) == 0) return src; } if(!create) return NULL; src = malloc(sizeof(struct source)); if(src == NULL) { zlog_err("malloc(source): %s", safe_strerror(errno)); return NULL; } memcpy(src->id, id, 8); memcpy(src->prefix, p, 16); src->plen = plen; src->seqno = seqno; src->metric = INFINITY; src->time = babel_now.tv_sec; src->route_count = 0; src->next = srcs; srcs = src; return src; } struct source * retain_source(struct source *src) { assert(src->route_count < 0xffff); src->route_count++; return src; } void release_source(struct source *src) { assert(src->route_count > 0); src->route_count--; } int flush_source(struct source *src) { if(src->route_count > 0) /* The source is in use by a route. */ return 0; if(srcs == src) { srcs = src->next; } else { struct source *previous = srcs; while(previous->next != src) previous = previous->next; previous->next = src->next; } free(src); return 1; } void update_source(struct source *src, unsigned short seqno, unsigned short metric) { if(metric >= INFINITY) return; /* If a source is expired, pretend that it doesn't exist and update it unconditionally. This makes ensures that old data will eventually be overridden, and prevents us from getting stuck if a router loses its sequence number. */ if(src->time < babel_now.tv_sec - SOURCE_GC_TIME || seqno_compare(src->seqno, seqno) < 0 || (src->seqno == seqno && src->metric > metric)) { src->seqno = seqno; src->metric = metric; } src->time = babel_now.tv_sec; } void expire_sources() { struct source *src; src = srcs; while(src) { if(src->time > babel_now.tv_sec) /* clock stepped */ src->time = babel_now.tv_sec; if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) { struct source *old = src; src = src->next; flush_source(old); continue; } src = src->next; } } void check_sources_released(void) { struct source *src; for(src = srcs; src; src = src->next) { if(src->route_count != 0) fprintf(stderr, "Warning: source %s %s has refcount %d.\n", format_eui64(src->id), format_prefix(src->prefix, src->plen), (int)src->route_count); } } quagga-0.99.22.4/babeld/source.h0000644000175000017500000000517012177450262013120 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek 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 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. */ #ifndef BABEL_SOURCE_H #define BABEL_SOURCE_H #define SOURCE_GC_TIME 200 struct source { struct source *next; unsigned char id[8]; unsigned char prefix[16]; unsigned char plen; unsigned short seqno; unsigned short metric; unsigned short route_count; time_t time; }; struct source *find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, int create, unsigned short seqno); struct source *retain_source(struct source *src); void release_source(struct source *src); int flush_source(struct source *src); void update_source(struct source *src, unsigned short seqno, unsigned short metric); void expire_sources(void); void check_sources_released(void); #endif quagga-0.99.22.4/babeld/util.c0000644000175000017500000002516212177450262012573 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include #include #include #include #include #include #include #include #include #include #include #include "babel_main.h" #include "babeld.h" #include "util.h" unsigned roughly(unsigned value) { return value * 3 / 4 + random() % (value / 2); } /* d = s1 - s2 */ void timeval_minus(struct timeval *d, const struct timeval *s1, const struct timeval *s2) { if(s1->tv_usec >= s2->tv_usec) { d->tv_usec = s1->tv_usec - s2->tv_usec; d->tv_sec = s1->tv_sec - s2->tv_sec; } else { d->tv_usec = s1->tv_usec + 1000000 - s2->tv_usec; d->tv_sec = s1->tv_sec - s2->tv_sec - 1; } } unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) { if(s1->tv_sec < s2->tv_sec) return 0; /* Avoid overflow. */ if(s1->tv_sec - s2->tv_sec > 2000000) return 2000000000; if(s1->tv_sec > s2->tv_sec) return (unsigned)((unsigned)(s1->tv_sec - s2->tv_sec) * 1000 + ((int)s1->tv_usec - s2->tv_usec) / 1000); if(s1->tv_usec <= s2->tv_usec) return 0; return (unsigned)(s1->tv_usec - s2->tv_usec) / 1000u; } /* d = s + msecs */ void timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs) { int usecs; d->tv_sec = s->tv_sec + msecs / 1000; usecs = s->tv_usec + (msecs % 1000) * 1000; if(usecs < 1000000) { d->tv_usec = usecs; } else { d->tv_usec = usecs - 1000000; d->tv_sec++; } } void set_timeout(struct timeval *timeout, int msecs) { timeval_add_msec(timeout, &babel_now, roughly(msecs)); } /* returns <0 if "s1" < "s2", etc. */ int timeval_compare(const struct timeval *s1, const struct timeval *s2) { if(s1->tv_sec < s2->tv_sec) return -1; else if(s1->tv_sec > s2->tv_sec) return 1; else if(s1->tv_usec < s2->tv_usec) return -1; else if(s1->tv_usec > s2->tv_usec) return 1; else return 0; } /* set d at min(d, s) */ /* {0, 0} represents infinity */ void timeval_min(struct timeval *d, const struct timeval *s) { if(s->tv_sec == 0) return; if(d->tv_sec == 0 || timeval_compare(d, s) > 0) { *d = *s; } } /* set d to min(d, x) with x in [secs, secs+1] */ void timeval_min_sec(struct timeval *d, time_t secs) { if(d->tv_sec == 0 || d->tv_sec > secs) { d->tv_sec = secs; d->tv_usec = random() % 1000000; } } /* parse a float value in second and return the corresponding mili-seconds. For example: parse_msec("12.342345") returns 12342 */ int parse_msec(const char *string) { unsigned int in, fl; int i, j; in = fl = 0; i = 0; while(string[i] == ' ' || string[i] == '\t') i++; while(string[i] >= '0' && string[i] <= '9') { in = in * 10 + string[i] - '0'; i++; } if(string[i] == '.') { i++; j = 0; while(string[i] >= '0' && string[i] <= '9') { fl = fl * 10 + string[i] - '0'; i++; j++; } while(j > 3) { fl /= 10; j--; } while(j < 3) { fl *= 10; j++; } } while(string[i] == ' ' || string[i] == '\t') i++; if(string[i] == '\0') return in * 1000 + fl; return -1; } int in_prefix(const unsigned char *restrict address, const unsigned char *restrict prefix, unsigned char plen) { unsigned char m; if(plen > 128) plen = 128; if(memcmp(address, prefix, plen / 8) != 0) return 0; if(plen % 8 == 0) return 1; m = 0xFF << (8 - (plen % 8)); return ((address[plen / 8] & m) == (prefix[plen / 8] & m)); } unsigned char * mask_prefix(unsigned char *restrict ret, const unsigned char *restrict prefix, unsigned char plen) { if(plen >= 128) { memcpy(ret, prefix, 16); return ret; } memset(ret, 0, 16); memcpy(ret, prefix, plen / 8); if(plen % 8 != 0) ret[plen / 8] = (prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF)); return ret; } static const unsigned char v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; static const unsigned char llprefix[16] = {0xFE, 0x80}; const char * format_address(const unsigned char *address) { static char buf[4][INET6_ADDRSTRLEN]; static int i = 0; i = (i + 1) % 4; if(v4mapped(address)) inet_ntop(AF_INET, address + 12, buf[i], INET6_ADDRSTRLEN); else inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN); return buf[i]; } const char * format_prefix(const unsigned char *prefix, unsigned char plen) { static char buf[4][INET6_ADDRSTRLEN + 4]; static int i = 0; int n; i = (i + 1) % 4; if(plen >= 96 && v4mapped(prefix)) { inet_ntop(AF_INET, prefix + 12, buf[i], INET6_ADDRSTRLEN); n = strlen(buf[i]); snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen - 96); } else { inet_ntop(AF_INET6, prefix, buf[i], INET6_ADDRSTRLEN); n = strlen(buf[i]); snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen); } return buf[i]; } const char * format_eui64(const unsigned char *eui) { static char buf[4][28]; static int i = 0; i = (i + 1) % 4; snprintf(buf[i], 28, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", eui[0], eui[1], eui[2], eui[3], eui[4], eui[5], eui[6], eui[7]); return buf[i]; } const char *format_bool(const int b) { return b ? "true" : "false"; } int parse_address(const char *address, unsigned char *addr_r, int *af_r) { struct in_addr ina; struct in6_addr ina6; int rc; rc = inet_pton(AF_INET, address, &ina); if(rc > 0) { memcpy(addr_r, v4prefix, 12); memcpy(addr_r + 12, &ina, 4); if(af_r) *af_r = AF_INET; return 0; } rc = inet_pton(AF_INET6, address, &ina6); if(rc > 0) { memcpy(addr_r, &ina6, 16); if(af_r) *af_r = AF_INET6; return 0; } return -1; } int parse_eui64(const char *eui, unsigned char *eui_r) { int n; n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); if(n == 8) return 0; n = sscanf(eui, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx", &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); if(n == 8) return 0; n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[5], &eui_r[6], &eui_r[7]); if(n == 6) { eui_r[3] = 0xFF; eui_r[4] = 0xFE; return 0; } return -1; } int wait_for_fd(int direction, int fd, int msecs) { fd_set fds; int rc; struct timeval tv; tv.tv_sec = msecs / 1000; tv.tv_usec = (msecs % 1000) * 1000; FD_ZERO(&fds); FD_SET(fd, &fds); if(direction) rc = select(fd + 1, NULL, &fds, NULL, &tv); else rc = select(fd + 1, &fds, NULL, NULL, &tv); return rc; } int martian_prefix(const unsigned char *prefix, int plen) { return (plen >= 8 && prefix[0] == 0xFF) || (plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) || (plen >= 128 && memcmp(prefix, zeroes, 15) == 0 && (prefix[15] == 0 || prefix[15] == 1)) || (plen >= 96 && v4mapped(prefix) && ((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) || (plen >= 100 && (prefix[12] & 0xE0) == 0xE0))); } int linklocal(const unsigned char *address) { return memcmp(address, llprefix, 8) == 0; } int v4mapped(const unsigned char *address) { return memcmp(address, v4prefix, 12) == 0; } void v4tov6(unsigned char *dst, const unsigned char *src) { memcpy(dst, v4prefix, 12); memcpy(dst + 12, src, 4); } void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src) { memcpy(dest, v4prefix, 12); memcpy(dest + 12, src, 4); assert(v4mapped(dest)); } void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src) { assert(v4mapped(src)); memcpy(dest, src + 12, 4); } void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src) { memcpy(dest, src, 16); } void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src) { memcpy(dest, src, 16); } int daemonise() { int rc; fflush(stdout); fflush(stderr); rc = fork(); if(rc < 0) return -1; if(rc > 0) exit(0); rc = setsid(); if(rc < 0) return -1; return 1; } quagga-0.99.22.4/babeld/util.h0000644000175000017500000001462512177450262012602 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include "babeld.h" #include "babel_main.h" #include "log.h" #if defined(i386) || defined(__mc68020__) || defined(__x86_64__) #define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0) #define DO_NTOHL(_d, _s) do{ _d = ntohl(*(const unsigned*)(_s)); } while(0) #define DO_HTONS(_d, _s) do{ *(unsigned short*)(_d) = htons(_s); } while(0) #define DO_HTONL(_d, _s) do{ *(unsigned*)(_d) = htonl(_s); } while(0) /* Some versions of gcc seem to be buggy, and ignore the packed attribute. Disable this code until the issue is clarified. */ /* #elif defined __GNUC__*/ #elif 0 struct __us { unsigned short x __attribute__((packed)); }; #define DO_NTOHS(_d, _s) \ do { _d = ntohs(((const struct __us*)(_s))->x); } while(0) #define DO_HTONS(_d, _s) \ do { ((struct __us*)(_d))->x = htons(_s); } while(0) #else #define DO_NTOHS(_d, _s) \ do { short _dd; \ memcpy(&(_dd), (_s), 2); \ _d = ntohs(_dd); } while(0) #define DO_HTONS(_d, _s) \ do { unsigned short _dd; \ _dd = htons(_s); \ memcpy((_d), &(_dd), 2); } while(0) #endif static inline int seqno_compare(unsigned short s1, unsigned short s2) { if(s1 == s2) return 0; else return ((s2 - s1) & 0x8000) ? 1 : -1; } static inline short seqno_minus(unsigned short s1, unsigned short s2) { return (short)((s1 - s2) & 0xFFFF); } static inline unsigned short seqno_plus(unsigned short s, int plus) { return ((s + plus) & 0xFFFF); } unsigned roughly(unsigned value); void timeval_minus(struct timeval *d, const struct timeval *s1, const struct timeval *s2); unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) ATTRIBUTE ((pure)); void timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs); void set_timeout (struct timeval *timeout, int msecs); int timeval_compare(const struct timeval *s1, const struct timeval *s2) ATTRIBUTE ((pure)); void timeval_min(struct timeval *d, const struct timeval *s); void timeval_min_sec(struct timeval *d, time_t secs); int parse_msec(const char *string) ATTRIBUTE ((pure)); int in_prefix(const unsigned char *restrict address, const unsigned char *restrict prefix, unsigned char plen) ATTRIBUTE ((pure)); unsigned char *mask_prefix(unsigned char *restrict ret, const unsigned char *restrict prefix, unsigned char plen); const char *format_address(const unsigned char *address); const char *format_prefix(const unsigned char *address, unsigned char prefix); const char *format_eui64(const unsigned char *eui); const char *format_bool(const int b); int parse_address(const char *address, unsigned char *addr_r, int *af_r); int parse_eui64(const char *eui, unsigned char *eui_r); int wait_for_fd(int direction, int fd, int msecs); int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure)); int linklocal(const unsigned char *address) ATTRIBUTE ((pure)); int v4mapped(const unsigned char *address) ATTRIBUTE ((pure)); void v4tov6(unsigned char *dst, const unsigned char *src); void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src); void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src); void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src); void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src); int daemonise(void); /* If debugging is disabled, we want to avoid calling format_address for every omitted debugging message. So debug is a macro. But vararg macros are not portable. */ #if defined NO_DEBUG #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(...) do {} while(0) #elif defined __GNUC__ #define debugf(_args...) do {} while(0) #else static inline void debugf(int level, const char *format, ...) { return; } #endif #else /* NO_DEBUG */ /* some levels */ #define BABEL_DEBUG_COMMON (1 << 0) #define BABEL_DEBUG_KERNEL (1 << 1) #define BABEL_DEBUG_FILTER (1 << 2) #define BABEL_DEBUG_TIMEOUT (1 << 3) #define BABEL_DEBUG_IF (1 << 4) #define BABEL_DEBUG_ROUTE (1 << 5) #define BABEL_DEBUG_ALL (0xFFFF) #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(level, ...) \ do { \ if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \ } while(0) #elif defined __GNUC__ #define debugf(level, _args...) \ do { \ if(UNLIKELY(debug & level)) zlog_debug(_args); \ } while(0) #else static inline void debugf(int level, const char *format, ...) { return; } #endif #endif /* NO_DEBUG */ quagga-0.99.22.4/babeld/xroute.c0000644000175000017500000001666212177450262013151 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ #include #include "if.h" #include "log.h" #include "babeld.h" #include "kernel.h" #include "neighbour.h" #include "message.h" #include "route.h" #include "xroute.h" #include "util.h" #include "babel_interface.h" static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto, int send_updates); static struct xroute *xroutes; static int numxroutes = 0, maxxroutes = 0; /* Add redistributed route to Babel table. */ int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex, struct in_addr *nexthop) { unsigned char uchar_prefix[16]; inaddr_to_uchar(uchar_prefix, &prefix->prefix); debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra."); xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96, api->metric, ifindex, 0, 1); return 0; } /* Remove redistributed route from Babel table. */ int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex) { unsigned char uchar_prefix[16]; struct xroute *xroute = NULL; inaddr_to_uchar(uchar_prefix, &prefix->prefix); xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96); if (xroute != NULL) { debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); flush_xroute(xroute); } return 0; } /* Add redistributed route to Babel table. */ int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex, struct in6_addr *nexthop) { unsigned char uchar_prefix[16]; in6addr_to_uchar(uchar_prefix, &prefix->prefix); debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra."); xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, 0, 1); return 0; } /* Remove redistributed route from Babel table. */ int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex) { unsigned char uchar_prefix[16]; struct xroute *xroute = NULL; in6addr_to_uchar(uchar_prefix, &prefix->prefix); xroute = find_xroute(uchar_prefix, prefix->prefixlen); if (xroute != NULL) { debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra)."); flush_xroute(xroute); } return 0; } struct xroute * find_xroute(const unsigned char *prefix, unsigned char plen) { int i; for(i = 0; i < numxroutes; i++) { if(xroutes[i].plen == plen && memcmp(xroutes[i].prefix, prefix, 16) == 0) return &xroutes[i]; } return NULL; } void flush_xroute(struct xroute *xroute) { int i; i = xroute - xroutes; assert(i >= 0 && i < numxroutes); if(i != numxroutes - 1) memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute)); numxroutes--; VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute)); if(numxroutes == 0) { free(xroutes); xroutes = NULL; maxxroutes = 0; } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) { struct xroute *new_xroutes; int n = maxxroutes / 2; new_xroutes = realloc(xroutes, n * sizeof(struct xroute)); if(new_xroutes == NULL) return; xroutes = new_xroutes; maxxroutes = n; } } static int add_xroute(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto) { struct xroute *xroute = find_xroute(prefix, plen); if(xroute) { if(xroute->metric <= metric) return 0; xroute->metric = metric; return 1; } if(numxroutes >= maxxroutes) { struct xroute *new_xroutes; int n = maxxroutes < 1 ? 8 : 2 * maxxroutes; new_xroutes = xroutes == NULL ? malloc(n * sizeof(struct xroute)) : realloc(xroutes, n * sizeof(struct xroute)); if(new_xroutes == NULL) return -1; maxxroutes = n; xroutes = new_xroutes; } memcpy(xroutes[numxroutes].prefix, prefix, 16); xroutes[numxroutes].plen = plen; xroutes[numxroutes].metric = metric; xroutes[numxroutes].ifindex = ifindex; xroutes[numxroutes].proto = proto; numxroutes++; return 1; } /* Returns an overestimate of the number of xroutes. */ int xroutes_estimate() { return numxroutes; } void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure) { int i; for(i = 0; i < numxroutes; i++) (*f)(&xroutes[i], closure); } /* add an xroute, verifying some conditions; return 0 if there is no changes */ static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto, int send_updates) { int rc; if(martian_prefix(prefix, plen)) return 0; metric = redistribute_filter(prefix, plen, ifindex, proto); if(metric < INFINITY) { rc = add_xroute(prefix, plen, metric, ifindex, proto); if(rc > 0) { struct babel_route *route; route = find_installed_route(prefix, plen); if(route) { if(allow_duplicates < 0 || metric < allow_duplicates) uninstall_route(route); } if(send_updates) send_update(NULL, 0, prefix, plen); return 1; } } return 0; } quagga-0.99.22.4/babeld/xroute.h0000644000175000017500000000544112177450262013147 00000000000000/* * 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. * * This 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 . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek 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 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. */ struct xroute { unsigned char prefix[16]; unsigned char plen; unsigned short metric; unsigned int ifindex; int proto; }; struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); void flush_xroute(struct xroute *xroute); int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex, struct in_addr *nexthop); int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex); int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex, struct in6_addr *nexthop); int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex); int xroutes_estimate(void); void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure); quagga-0.99.22.4/bgpd/0000755000175000017500000000000012211704576011226 500000000000000quagga-0.99.22.4/bgpd/BGP4-MIB.txt0000644000175000017500000010734012000052240012771 00000000000000 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-0.99.22.4/bgpd/Makefile.am0000644000175000017500000000225312177450262013205 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbgp.a sbin_PROGRAMS = bgpd libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgpd_SOURCES = bgp_main.c bgpd_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-0.99.22.4/bgpd/Makefile.in0000644000175000017500000006022612211704501013205 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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) subdir = bgpd DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru 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_mplsvpn.$(OBJEXT) bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) \ bgp_table.$(OBJEXT) bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) \ bgp_mpath.$(OBJEXT) libbgp_a_OBJECTS = $(am_libbgp_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am_bgpd_OBJECTS = bgp_main.$(OBJEXT) bgpd_OBJECTS = $(am_bgpd_OBJECTS) bgpd_DEPENDENCIES = libbgp.a ../lib/libzebra.la 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) DIST_SOURCES = $(libbgp_a_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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgpd_SOURCES = bgp_main.c bgpd_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 .PRECIOUS: 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) -rm -f libbgp.a $(libbgp_a_AR) libbgp.a $(libbgp_a_OBJECTS) $(libbgp_a_LIBADD) $(RANLIB) libbgp.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 bgpd$(EXEEXT): $(bgpd_OBJECTS) $(bgpd_DEPENDENCIES) $(EXTRA_bgpd_DEPENDENCIES) @rm -f bgpd$(EXEEXT) $(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_clist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_community.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_damp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_dump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_ecommunity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_fsm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_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_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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/bgpd/bgp_advertise.c0000644000175000017500000002256712132522417014136 00000000000000/* BGP advertisement and adjacency Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "thread.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_mplsvpn.h" /* BGP advertise attribute is used for pack same attribute update into one packet. To do that we maintain attribute hash in struct peer. */ static struct bgp_advertise_attr * baa_new (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; adv = adj->adv; baa = adv->baa; next = NULL; if (baa) { /* Unlink myself from advertise attribute FIFO. */ bgp_advertise_delete (baa, adv); /* Fetch next advertise candidate. */ next = baa->adv; /* Unintern BGP advertise attribute. */ bgp_advertise_unintern (peer->hash[afi][safi], baa); } /* Unlink myself from advertisement FIFO. */ FIFO_DEL (adv); /* Free memory. */ bgp_advertise_free (adj->adv); adj->adv = NULL; return next; } void bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, struct bgp_info *binfo) { struct bgp_adj_out *adj = NULL; struct bgp_advertise *adv; 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); 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. */ 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); } void bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) { struct bgp_adj_in *adj; for (adj = rn->adj_in; adj; adj = adj->next) if (adj->peer == peer) break; if (! adj) return; bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); } void bgp_sync_init (struct peer *peer) { afi_t afi; safi_t safi; struct bgp_synchronize *sync; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { sync = XCALLOC (MTYPE_BGP_SYNCHRONISE, sizeof (struct bgp_synchronize)); FIFO_INIT (&sync->update); FIFO_INIT (&sync->withdraw); FIFO_INIT (&sync->withdraw_low); peer->sync[afi][safi] = sync; peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); } } void bgp_sync_delete (struct peer *peer) { afi_t afi; safi_t safi; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { if (peer->sync[afi][safi]) XFREE (MTYPE_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-0.99.22.4/bgpd/bgp_advertise.h0000644000175000017500000001051212132522417014126 00000000000000/* 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 /* BGP advertise FIFO. */ struct bgp_advertise_fifo { struct bgp_advertise *next; struct bgp_advertise *prev; }; /* BGP advertise attribute. */ struct bgp_advertise_attr { /* Head of advertisement pointer. */ struct bgp_advertise *adv; /* Reference counter. */ unsigned long refcnt; /* Attribute pointer to be announced. */ struct attr *attr; }; struct bgp_advertise { /* FIFO for advertisement. */ struct bgp_advertise_fifo fifo; /* Link list for same attribute advertise. */ struct bgp_advertise *next; struct bgp_advertise *prev; /* Prefix information. */ struct bgp_node *rn; /* Reference pointer. */ struct bgp_adj_out *adj; /* Advertisement attribute. */ struct bgp_advertise_attr *baa; /* BGP info. */ struct bgp_info *binfo; }; /* BGP adjacency out. */ struct bgp_adj_out { /* Lined list pointer. */ struct bgp_adj_out *next; struct bgp_adj_out *prev; /* Advertised peer. */ struct peer *peer; /* Advertised attribute. */ struct attr *attr; /* Advertisement information. */ struct bgp_advertise *adv; }; /* BGP adjacency in. */ struct bgp_adj_in { /* Linked list pointer. */ struct bgp_adj_in *next; struct bgp_adj_in *prev; /* Received peer. */ struct peer *peer; /* Received attribute. */ struct attr *attr; }; /* BGP advertisement list. */ struct bgp_synchronize { struct bgp_advertise_fifo update; struct bgp_advertise_fifo withdraw; struct bgp_advertise_fifo withdraw_low; }; /* BGP adjacency linked list. */ #define BGP_INFO_ADD(N,A,TYPE) \ do { \ (A)->prev = NULL; \ (A)->next = (N)->TYPE; \ if ((N)->TYPE) \ (N)->TYPE->prev = (A); \ (N)->TYPE = (A); \ } while (0) #define BGP_INFO_DEL(N,A,TYPE) \ do { \ if ((A)->next) \ (A)->next->prev = (A)->prev; \ if ((A)->prev) \ (A)->prev->next = (A)->next; \ else \ (N)->TYPE = (A)->next; \ } while (0) #define BGP_ADJ_IN_ADD(N,A) BGP_INFO_ADD(N,A,adj_in) #define BGP_ADJ_IN_DEL(N,A) BGP_INFO_DEL(N,A,adj_in) #define BGP_ADJ_OUT_ADD(N,A) BGP_INFO_ADD(N,A,adj_out) #define BGP_ADJ_OUT_DEL(N,A) BGP_INFO_DEL(N,A,adj_out) /* Prototypes. */ 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 void 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-0.99.22.4/bgpd/bgp_aspath.c0000644000175000017500000013451512211704467013432 00000000000000/* 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 "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))); } /* 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) XFREE (MTYPE_AS_SEG_DATA, 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 */ newas = assegment_data_new (seg->length + num); for (i = 0; i < num; i++) newas[i] = asnum; memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); XFREE (MTYPE_AS_SEG_DATA, 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 (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 && (seg->as[i] < BGP_PRIVATE_AS_MIN || seg->as[i] > BGP_PRIVATE_AS_MAX)) highest = seg->as[i]; seg = seg->next; } return highest; } /* 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, AS_SEGMENT_MAX, use32bit); written += AS_SEGMENT_MAX; bytes += ASSEGMENT_SIZE (written, 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; 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; } /* 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 ( (seg->as[i] < BGP_PRIVATE_AS_MIN) || (seg->as[i] > BGP_PRIVATE_AS_MAX) ) 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); /* 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_one_as (struct aspath *aspath, as_t asno, u_char type) { struct assegment *assegment = aspath->segments; /* In case of empty aspath. */ if (assegment == NULL || assegment->length == 0) { aspath->segments = assegment_new (type, 1); aspath->segments->as[0] = asno; if (assegment) assegment_free (assegment); return aspath; } if (assegment->type == type) aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1); else { /* create new segment * push it onto head of aspath's segment chain */ struct assegment *newsegment; newsegment = assegment_new (type, 1); newsegment->as[0] = asno; newsegment->next = assegment; aspath->segments = newsegment; } return aspath; } /* Add specified AS to the leftmost of aspath. */ struct aspath * aspath_add_seq (struct aspath *aspath, as_t asno) { return aspath_add_one_as (aspath, asno, AS_SEQUENCE); } /* Compare leftmost AS value for MED check. If as1's leftmost AS and as2's leftmost AS is same return 1. */ int aspath_cmp_left (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; /* 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_one_as (aspath, asno, AS_CONFED_SEQUENCE); } /* 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 (32767, aspath_key_make, aspath_cmp); } void aspath_finish (void) { 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) ", 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-0.99.22.4/bgpd/bgp_aspath.h0000644000175000017500000001011112177450262013422 00000000000000/* 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 /* 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 /* 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_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); 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 (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 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-0.99.22.4/bgpd/bgp_attr.c0000644000175000017500000023120012177450262013113 00000000000000/* 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 "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" /* Attribute strings for logging. */ 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" }, }; 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 const size_t attr_flag_str_max = array_size(attr_flag_str); 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) { if (cluster->refcnt) cluster->refcnt--; if (cluster->refcnt == 0) { hash_release (cluster_hash, cluster); cluster_free (cluster); } } static void cluster_init (void) { cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); } static void cluster_finish (void) { hash_free (cluster_hash); cluster_hash = NULL; } /* 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) { if (transit->refcnt) transit->refcnt--; if (transit->refcnt == 0) { hash_release (transit_hash, transit); transit_free (transit); } } 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_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) { 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; } else if (orig->extra) { new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; } } 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); } if (attr->aspath) MIX(aspath_key_make (attr->aspath)); if (attr->community) MIX(community_hash_make (attr->community)); if (extra) { 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)); #ifdef HAVE_IPV6 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); #endif /* HAVE_IPV6 */ } 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 #ifdef HAVE_IPV6 && 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) #endif /* HAVE_IPV6 */ && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) && ae1->ecommunity == ae2->ecommunity && ae1->cluster == ae2->cluster && ae1->transit == ae2->transit) 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); } static void attrhash_finish (void) { 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; } 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->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->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); #ifdef HAVE_IPV6 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; #endif return attr; } /* Make network statement's attribute. */ struct attr * bgp_attr_default_intern (u_char origin) { struct attr attr; struct attr *new; bgp_attr_default_set(&attr, origin); new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); aspath_unintern (&new->aspath); return new; } struct attr * bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, struct aspath *aspath, struct community *community, int as_set) { struct attr attr; struct attr *new; 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; #ifdef HAVE_IPV6 attre.mp_nexthop_len = IPV6_MAX_BYTELEN; #endif if (! as_set) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) 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, BGP_ATTR_AS_PATH); if (attr->community) community_unintern (&attr->community); UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES); if (attr->extra) { if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES); if (attr->extra->cluster) cluster_unintern (attr->extra->cluster); UNSET_FLAG(attr->flag, 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); if (attr->community && ! attr->community->refcnt) community_free (attr->community); if (attr->extra) { struct attr_extra *attre = attr->extra; if (attre->ecommunity && ! attre->ecommunity->refcnt) ecommunity_free (&attre->ecommunity); if (attre->cluster && ! attre->cluster->refcnt) cluster_free (attre->cluster); if (attre->transit && ! attre->transit->refcnt) transit_free (attre->transit); } } /* Implement draft-scudder-idr-optional-transitive 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); /* 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 */ 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, }; static const size_t attr_flags_values_max = sizeof (attr_flags_values) / sizeof (attr_flags_values[0]); 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)) { char buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop_h, 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 (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)))) { if (!attr->aspath) return BGP_ATTR_PARSE_PROCEED; 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; int ret; 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; } /* 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; } /* 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; #ifdef HAVE_IPV6 case 16: stream_get (&attre->mp_nexthop_global, s, 16); break; case 32: stream_get (&attre->mp_nexthop_global, s, 16); 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; #endif /* HAVE_IPV6 */ default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR; } if (!LEN_LEFT) { zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, peer->host); return BGP_ATTR_PARSE_ERROR; } { 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; } if (safi != SAFI_MPLS_LABELED_VPN) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); if (ret < 0) { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", __func__, peer->host); return BGP_ATTR_PARSE_ERROR; } } 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); 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; int ret; struct peer *const peer = args->peer; 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; afi = stream_getw (s); safi = stream_getc (s); withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; if (safi != SAFI_MPLS_LABELED_VPN) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); if (ret < 0) return BGP_ATTR_PARSE_ERROR; } 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); 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->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; } /* 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; } /* 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 = { 0 }; /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); /* End pointer of BGP attribute. */ endp = BGP_INPUT_PNT (peer) + size; /* Get attributes to the end of attribute length. */ while (BGP_INPUT_PNT (peer) < endp) { /* Check remaining length check.*/ if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) { /* 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); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); 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_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; default: ret = bgp_attr_unknown (&attr_args); break; } /* If hard error occured 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)); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); 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; } /* * 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. */ if (bgp_attr_munge_as4_attrs (peer, attr, as4_path, as4_aggregator, &as4_aggregator_addr)) { 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; } /* Well-known attribute check. */ int bgp_attr_check (struct peer *peer, struct attr *attr) { u_char type = 0; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) type = BGP_ATTR_ORIGIN; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) type = BGP_ATTR_AS_PATH; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) type = BGP_ATTR_NEXT_HOP; if (peer->sort == BGP_PEER_IBGP && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) type = BGP_ATTR_LOCAL_PREF; if (type) { zlog (peer->log, LOG_WARNING, "%s Missing well-known attribute %d.", peer->host, type); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MISS_ATTR, &type, 1); return BGP_ATTR_PARSE_ERROR; } return BGP_ATTR_PARSE_PROCEED; } int stream_put_prefix (struct stream *, struct prefix *); /* Make attribute packet. */ bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, u_char *tag) { 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); /* 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) { 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); } /* 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); } } #ifdef HAVE_IPV6 /* If p is IPv6 address put it into attribute. */ if (p->family == AF_INET6) { unsigned long sizep; struct attr_extra *attre = attr->extra; assert (attr->extra); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); stream_putc (s, 0); /* Marker: Attribute length. */ stream_putw (s, AFI_IP6); /* AFI */ stream_putc (s, safi); /* SAFI */ stream_putc (s, attre->mp_nexthop_len); if (attre->mp_nexthop_len == 16) stream_put (s, &attre->mp_nexthop_global, 16); else if (attre->mp_nexthop_len == 32) { stream_put (s, &attre->mp_nexthop_global, 16); stream_put (s, &attre->mp_nexthop_local, 16); } /* SNPA */ stream_putc (s, 0); /* Prefix write. */ stream_put_prefix (s, p); /* Set MP attribute length. */ stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } #endif /* HAVE_IPV6 */ if (p->family == AF_INET && safi == SAFI_MULTICAST) { unsigned long sizep; stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); stream_putc (s, 0); /* Marker: Attribute Length. */ stream_putw (s, AFI_IP); /* AFI */ stream_putc (s, SAFI_MULTICAST); /* SAFI */ stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); /* SNPA */ stream_putc (s, 0); /* Prefix write. */ stream_put_prefix (s, p); /* Set MP attribute length. */ stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } if (p->family == AF_INET && safi == SAFI_MPLS_VPN) { unsigned long sizep; stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); stream_putc (s, 0); /* Length of this attribute. */ stream_putw (s, AFI_IP); /* AFI */ stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */ stream_putc (s, 12); stream_putl (s, 0); stream_putl (s, 0); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); /* SNPA */ stream_putc (s, 0); /* Tag, RD, Prefix write. */ stream_putc (s, p->prefixlen + 88); stream_put (s, tag, 3); stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); /* Set MP attribute length. */ stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } /* Extended Communities attribute. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) { 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); } /* 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; } bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { unsigned long cp; unsigned long attrlen_pnt; bgp_size_t size; cp = stream_get_endp (s); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); attrlen_pnt = stream_get_endp (s); stream_putc (s, 0); /* Length of this attribute. */ stream_putw (s, family2afi (p->family)); if (safi == SAFI_MPLS_VPN) { /* SAFI */ stream_putc (s, SAFI_MPLS_LABELED_VPN); /* prefix. */ stream_putc (s, p->prefixlen + 88); stream_put (s, tag, 3); stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); } else { /* SAFI */ stream_putc (s, safi); /* prefix */ stream_put_prefix (s, p); } /* Set MP attribute length. */ size = stream_get_endp (s) - attrlen_pnt - 1; stream_putc_at (s, attrlen_pnt, size); return stream_get_endp (s) - cp; } /* Initialization of attribute. */ void bgp_attr_init (void) { aspath_init (); attrhash_init (); community_init (); ecommunity_init (); cluster_init (); transit_init (); } void bgp_attr_finish (void) { aspath_finish (); attrhash_finish (); community_finish (); ecommunity_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 #ifdef HAVE_IPV6 && prefix->family != AF_INET6 #endif /* HAVE_IPV6 */ ) { 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); } #ifdef HAVE_IPV6 /* 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); } #endif /* HAVE_IPV6 */ /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); } quagga-0.99.22.4/bgpd/bgp_attr.h0000644000175000017500000001413712132533566013130 00000000000000/* 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 /* Additional/uncommon BGP attributes. * lazily allocated as and when a struct attr * requires it. */ struct attr_extra { /* Multi-Protocol Nexthop, AFI IPv6 */ #ifdef HAVE_IPV6 struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_local; #endif /* HAVE_IPV6 */ /* Extended Communities attribute. */ struct ecommunity *ecommunity; /* Route-Reflector Cluster attribute */ struct cluster_list *cluster; /* Unknown transitive attribute. */ struct transit *transit; struct in_addr mp_nexthop_global_in; struct in_addr mp_nexthop_local_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; }; /* 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, } 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 int bgp_attr_check (struct peer *, struct attr *); 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); 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 bgp_size_t bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p, afi_t, safi_t, 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 *); #endif /* _QUAGGA_BGP_ATTR_H */ quagga-0.99.22.4/bgpd/bgp_clist.c0000644000175000017500000005242612132522417013263 00000000000000/* BGP community-list and extcommunity-list. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" /* Lookup master structure for community-list or extcommunity-list. */ struct community_list_master * community_list_master_lookup (struct community_list_handler *ch, int master) { if (ch) switch (master) { case COMMUNITY_LIST_MASTER: return &ch->community_list; case EXTCOMMUNITY_LIST_MASTER: return &ch->extcommunity_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 EXTCOMMUNITY_LIST_STANDARD: /* In case of standard extcommunity-list, configuration string is made by ecommunity_ecom2str(). */ if (entry->config) XFREE (MTYPE_ECOMMUNITY_STR, entry->config); if (entry->u.ecom) ecommunity_free (&entry->u.ecom); break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: if (entry->config) XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) bgp_regex_free (entry->reg); default: break; } XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry); } /* Allocate a new community-list. */ 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 EXTCOMMUNITY_LIST_STANDARD: if (ecommunity_cmp (entry->u.ecom, arg)) return entry; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, arg) == 0) return entry; break; default: break; } } return NULL; } /* Internal function to perform regular expression match for community attribute. */ static int community_regexp_match (struct community *com, regex_t * reg) { 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 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; } /* Delete community attribute using regular expression match. Return modified communites attribute. */ static struct community * community_regexp_delete (struct community *com, regex_t * reg) { int i; u_int32_t comval; /* Maximum is "65535:65535" + '\0'. */ char c[12]; const char *str; if (!com) return NULL; i = 0; while (i < com->size) { memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); comval = ntohl (comval); switch (comval) { case COMMUNITY_INTERNET: str = "internet"; break; case COMMUNITY_NO_EXPORT: str = "no-export"; break; case COMMUNITY_NO_ADVERTISE: str = "no-advertise"; break; case COMMUNITY_LOCAL_AS: str = "local-AS"; break; default: sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); str = c; break; } if (regexec (reg, str, 0, NULL, 0) == 0) community_del_val (com, com_nthval (com, i)); else i++; } return com; } /* When given community attribute matches to the community-list return 1 else return 0. */ int community_list_match (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (entry->style == COMMUNITY_LIST_STANDARD) { if (community_include (entry->u.com, COMMUNITY_INTERNET)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (community_match (com, entry->u.com)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == COMMUNITY_LIST_EXPANDED) { if (community_regexp_match (com, entry->reg)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } } return 0; } int ecommunity_list_match (struct ecommunity *ecom, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (entry->style == EXTCOMMUNITY_LIST_STANDARD) { if (ecommunity_match (ecom, entry->u.ecom)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) { if (ecommunity_regexp_match (ecom, entry->reg)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } } return 0; } /* Perform exact matching. In case of expanded community-list, do same thing as community_list_match(). */ int community_list_exact_match (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (entry->style == COMMUNITY_LIST_STANDARD) { if (community_include (entry->u.com, COMMUNITY_INTERNET)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (community_cmp (com, entry->u.com)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == COMMUNITY_LIST_EXPANDED) { if (community_regexp_match (com, entry->reg)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } } return 0; } /* 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; for (entry = list->head; entry; entry = entry->next) { if (entry->any) { if (entry->direct == COMMUNITY_PERMIT) { /* This is a tricky part. Currently only * route_set_community_delete() uses this function. In the * function com->size is zero, it free the community * structure. */ com->size = 0; } return com; } if ((entry->style == COMMUNITY_LIST_STANDARD) && (community_include (entry->u.com, COMMUNITY_INTERNET) || community_match (com, entry->u.com) )) { if (entry->direct == COMMUNITY_PERMIT) community_delete (com, entry->u.com); else break; } else if ((entry->style == COMMUNITY_LIST_EXPANDED) && community_regexp_match (com, entry->reg)) { if (entry->direct == COMMUNITY_PERMIT) community_regexp_delete (com, entry->reg); else break; } } 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 COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, new->config) == 0) return 1; break; default: break; } } return 0; } /* Set community-list. */ int community_list_set (struct community_list_handler *ch, 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; } /* 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->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-0.99.22.4/bgpd/bgp_clist.h0000644000175000017500000001112012132522417013252 00000000000000/* 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 /* Community-list deny and permit. */ #define COMMUNITY_DENY 0 #define COMMUNITY_PERMIT 1 /* Number and string based community-list name. */ #define COMMUNITY_LIST_STRING 0 #define COMMUNITY_LIST_NUMBER 1 /* Community-list entry types. */ #define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */ #define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */ #define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */ #define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */ /* Community-list. */ struct community_list { /* Name of the community-list. */ char *name; /* String or number. */ int sort; /* Link to upper list. */ struct community_list_list *parent; /* Linked list for other community-list. */ struct community_list *next; struct community_list *prev; /* Community-list entry in this community-list. */ struct community_entry *head; struct community_entry *tail; }; /* Each entry in community-list. */ struct community_entry { struct community_entry *next; struct community_entry *prev; /* Permit or deny. */ u_char direct; /* Standard or expanded. */ u_char style; /* Any match. */ u_char any; /* Community structure. */ union { struct community *com; struct ecommunity *ecom; } u; /* Configuration string. */ char *config; /* Expanded community-list regular expression. */ regex_t *reg; }; /* Linked list of community-list. */ struct community_list_list { struct community_list *head; struct community_list *tail; }; /* Master structure of community-list and extcommunity-list. */ struct community_list_master { struct community_list_list num; struct community_list_list str; }; /* Community-list handler. community_list_init() returns this structure as handler. */ struct community_list_handler { /* Community-list. */ struct community_list_master community_list; /* Exteded community-list. */ struct community_list_master extcommunity_list; }; /* Error code of community-list. */ #define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1 #define COMMUNITY_LIST_ERR_MALFORMED_VAL -2 #define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3 #define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4 /* Handler. */ extern struct community_list_handler *bgp_clist; /* Prototypes. */ 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 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 community_list_exact_match (struct community *, struct community_list *); extern struct community * community_list_match_delete (struct community *, struct community_list *); #endif /* _QUAGGA_BGP_CLIST_H */ quagga-0.99.22.4/bgpd/bgp_community.c0000644000175000017500000003212212177450262014167 00000000000000/* 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) memcpy (com->val + i, com->val + (i + 1), c * sizeof (*val)); com->size--; if (com->size > 0) com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); else { XFREE (MTYPE_COMMUNITY_VAL, com->val); com->val = NULL; } return; } i++; } } /* Delete all communities listed in com2 from com1 */ struct community * community_delete (struct community *com1, struct community *com2) { int i = 0; while(i < com2->size) { community_del_val (com1, com2->val + i); i++; } return com1; } /* Callback function from qsort(). */ 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; } static 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-0.99.22.4/bgpd/bgp_community.h0000644000175000017500000000555712132522417014201 00000000000000/* 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); #endif /* _QUAGGA_BGP_COMMUNITY_H */ quagga-0.99.22.4/bgpd/bgp_damp.c0000644000175000017500000004203612177450262013071 00000000000000/* BGP flap dampening Copyright (C) 2001 IP Infusion Inc. This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "prefix.h" #include "memory.h" #include "command.h" #include "log.h" #include "thread.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_advertise.h" /* Global variable to access damping configuration */ struct bgp_damp_config bgp_damp_cfg; 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 (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 (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 %ld%s", bgp_damp_cfg.half_life/60, VTY_NEWLINE); else vty_out (vty, " bgp dampening %ld %d %d %ld%s", bgp_damp_cfg.half_life/60, bgp_damp_cfg.reuse_limit, bgp_damp_cfg.suppress_value, bgp_damp_cfg.max_suppress_time/60, VTY_NEWLINE); } 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); } quagga-0.99.22.4/bgpd/bgp_damp.h0000644000175000017500000001061612132522417013066 00000000000000/* 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); #endif /* _QUAGGA_BGP_DAMP_H */ quagga-0.99.22.4/bgpd/bgp_debug.c0000644000175000017500000006403512177450262013241 00000000000000/* 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 "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 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; /* 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" }, }; const int bgp_status_msg_max = BGP_STATUS_MAX; /* BGP message type string. */ const char *bgp_type_str[] = { NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", "CAPABILITY" }; /* 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"}, }; static const int bgp_notify_msg_max = BGP_NOTIFY_MAX; 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"} }; static const int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX; 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"}, }; static const int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX; 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"}, }; static const int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX; 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"}, }; static const int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX; 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"}, }; static const int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX; /* 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]); #ifdef HAVE_IPV6 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)); } #endif /* HAVE_IPV6 */ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", attr->local_pref); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u", attr->med); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) snprintf (buf + strlen (buf), size - strlen (buf), ", community %s", community_str (attr->community)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_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_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 (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); 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); 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++; } 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_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, &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_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_all_cmd); install_element (ENABLE_NODE, &undebug_bgp_all_cmd); } quagga-0.99.22.4/bgpd/bgp_debug.h0000644000175000017500000000752312132522417013236 00000000000000/* 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 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; #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_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-0.99.22.4/bgpd/bgp_dump.c0000644000175000017500000005252412132522417013111 00000000000000/* 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 "bgpd/bgp_table.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_dump.h" enum bgp_dump_type { BGP_DUMP_ALL, BGP_DUMP_UPDATES, BGP_DUMP_ROUTES }; enum MRT_MSG_TYPES { MSG_NULL, MSG_START, /* sender is starting up */ MSG_DIE, /* receiver should shut down */ MSG_I_AM_DEAD, /* sender is shutting down */ MSG_PEER_DOWN, /* sender's peer is down */ MSG_PROTOCOL_BGP, /* msg is a BGP packet */ MSG_PROTOCOL_RIP, /* msg is a RIP packet */ MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */ MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */ MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */ MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */ MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */ MSG_TABLE_DUMP, /* routing table dump */ MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */ }; static int bgp_dump_interval_func (struct thread *); struct bgp_dump { enum bgp_dump_type type; char *filename; FILE *fp; unsigned int interval; char *interval_str; struct thread *t_interval; }; /* BGP packet dump output buffer. */ struct stream *bgp_dump_obuf; /* BGP dump strucuture for 'dump bgp all' */ struct bgp_dump bgp_dump_all; /* BGP dump structure for 'dump bgp updates' */ struct bgp_dump bgp_dump_updates; /* BGP dump structure for 'dump bgp routes' */ struct bgp_dump bgp_dump_routes; /* Dump whole BGP table is very heavy process. */ struct thread *t_bgp_dump_routes; /* Some define for BGP packet dump. */ 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 (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 (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) { time_t now; /* Set header. */ time (&now); /* Put dump packet header. */ stream_putl (obuf, now); stream_putw (obuf, type); stream_putw (obuf, subtype); stream_putl (obuf, 0); /* len */ } static void bgp_dump_set_size (struct stream *s, int type) { 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 = 0; 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); /* 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 */ stream_putw (obuf, listcount(bgp->peer)); /* 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); } #ifdef HAVE_IPV6 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); } #endif /* HAVE_IPV6 */ /* 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); } #ifdef HAVE_IPV6 else if (sockunion_family(&peer->su) == AF_INET6) { stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); } #endif /* HAVE_IPV6 */ /* 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); } /* Runs under child process. */ static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { struct stream *obuf; 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); obuf = bgp_dump_obuf; stream_reset(obuf); /* Walk down each BGP route. */ table = bgp->rib[afi][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { if(!rn->info) continue; stream_reset(obuf); /* MRT header */ if (afi == AFI_IP) { bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST); } #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST); } #endif /* HAVE_IPV6 */ /* 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); } #ifdef HAVE_IPV6 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); } #endif /* HAVE_IPV6 */ /* Save where we are now, so we can overwride the entry count later */ int sizep = stream_get_endp(obuf); /* Entry count */ uint16_t entry_count = 0; /* Entry count, note that this is overwritten later */ stream_putw(obuf, 0); for (info = rn->info; info; info = info->next) { entry_count++; /* 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); } /* Overwrite the entry count, now that we know the right number */ stream_putw_at (obuf, sizep, entry_count); seq++; 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); 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); #ifdef HAVE_IPV6 bgp_dump_routes_func (AFI_IP6, 0, seq); #endif /* HAVE_IPV6 */ /* 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); } #ifdef HAVE_IPV6 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); } #endif /* HAVE_IPV6 */ } /* Dump BGP status change. */ void bgp_dump_state (struct peer *peer, int status_old, int status_new) { struct stream *obuf; /* If dump file pointer is disabled return immediately. */ if (bgp_dump_all.fp == NULL) return; /* Make dump stream. */ obuf = bgp_dump_obuf; stream_reset (obuf); bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4); 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); } else { bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); } 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; 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; } /* Don't schedule duplicate dumps if the dump command is given twice */ if (interval == bgp_dump->interval && type == bgp_dump->type && path && bgp_dump->filename && !strcmp (path, bgp_dump->filename)) { return CMD_SUCCESS; } /* Set interval. */ bgp_dump->interval = interval; if (bgp_dump->interval_str) free (bgp_dump->interval_str); bgp_dump->interval_str = strdup (interval_str); } else { interval = 0; } /* Create interval thread. */ bgp_dump_interval_add (bgp_dump, interval); /* Set type. */ bgp_dump->type = type; /* Set file name. */ if (bgp_dump->filename) free (bgp_dump->filename); bgp_dump->filename = strdup (path); /* This should be called when interval is expired. */ bgp_dump_open_file (bgp_dump); return CMD_SUCCESS; } static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) { /* Set file name. */ if (bgp_dump->filename) { free (bgp_dump->filename); bgp_dump->filename = NULL; } /* This should be called when interval is expired. */ if (bgp_dump->fp) { fclose (bgp_dump->fp); bgp_dump->fp = NULL; } /* Create interval thread. */ if (bgp_dump->t_interval) { thread_cancel (bgp_dump->t_interval); bgp_dump->t_interval = NULL; } bgp_dump->interval = 0; if (bgp_dump->interval_str) { free (bgp_dump->interval_str); bgp_dump->interval_str = NULL; } return CMD_SUCCESS; } DEFUN (dump_bgp_all, dump_bgp_all_cmd, "dump bgp all PATH", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n" "Output filename\n") { return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL); } DEFUN (dump_bgp_all_interval, dump_bgp_all_interval_cmd, "dump bgp all PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n" "Output filename\n" "Interval of output\n") { return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]); } DEFUN (no_dump_bgp_all, no_dump_bgp_all_cmd, "no dump bgp all [PATH] [INTERVAL]", NO_STR "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n") { return bgp_dump_unset (vty, &bgp_dump_all); } DEFUN (dump_bgp_updates, dump_bgp_updates_cmd, "dump bgp updates PATH", "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n" "Output filename\n") { return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL); } DEFUN (dump_bgp_updates_interval, dump_bgp_updates_interval_cmd, "dump bgp updates PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n" "Output filename\n" "Interval of output\n") { return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]); } DEFUN (no_dump_bgp_updates, no_dump_bgp_updates_cmd, "no dump bgp updates [PATH] [INTERVAL]", NO_STR "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n") { return bgp_dump_unset (vty, &bgp_dump_updates); } DEFUN (dump_bgp_routes, dump_bgp_routes_cmd, "dump bgp routes-mrt PATH", "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n" "Output filename\n") { return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL); } DEFUN (dump_bgp_routes_interval, dump_bgp_routes_interval_cmd, "dump bgp routes-mrt PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n" "Output filename\n" "Interval of output\n") { return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]); } DEFUN (no_dump_bgp_routes, no_dump_bgp_routes_cmd, "no dump bgp routes-mrt [PATH] [INTERVAL]", NO_STR "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n") { return bgp_dump_unset (vty, &bgp_dump_routes); } /* BGP node structure. */ 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) { if (bgp_dump_all.interval_str) vty_out (vty, "dump bgp all %s %s%s", bgp_dump_all.filename, bgp_dump_all.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp all %s%s", bgp_dump_all.filename, VTY_NEWLINE); } if (bgp_dump_updates.filename) { if (bgp_dump_updates.interval_str) vty_out (vty, "dump bgp updates %s %s%s", bgp_dump_updates.filename, bgp_dump_updates.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp updates %s%s", bgp_dump_updates.filename, VTY_NEWLINE); } if (bgp_dump_routes.filename) { if (bgp_dump_routes.interval_str) vty_out (vty, "dump bgp routes-mrt %s %s%s", bgp_dump_routes.filename, bgp_dump_routes.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp routes-mrt %s%s", bgp_dump_routes.filename, VTY_NEWLINE); } return 0; } /* Initialize BGP packet dump functionality. */ void bgp_dump_init (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 + 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, &dump_bgp_all_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_all_cmd); install_element (CONFIG_NODE, &dump_bgp_updates_cmd); install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd); install_element (CONFIG_NODE, &dump_bgp_routes_cmd); install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); } void bgp_dump_finish (void) { stream_free (bgp_dump_obuf); bgp_dump_obuf = NULL; } quagga-0.99.22.4/bgpd/bgp_dump.h0000644000175000017500000000356212132522417013114 00000000000000/* 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 /* 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-0.99.22.4/bgpd/bgp_ecommunity.c0000644000175000017500000004207312177450262014342 00000000000000/* BGP Extended Communities Attribute Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "hash.h" #include "memory.h" #include "prefix.h" #include "command.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" #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_rt, ecommunity_token_soo, ecommunity_token_val, ecommunity_token_unknown }; /* 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; 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++; if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP && encode != ECOMMUNITY_ENCODE_AS4) { 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:%d", 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:%d", 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:%d", 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-0.99.22.4/bgpd/bgp_ecommunity.h0000644000175000017500000000575112177450262014351 00000000000000/* 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 /* Low-order octet of the Extended Communityes type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 /* 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-0.99.22.4/bgpd/bgp_filter.c0000644000175000017500000004010212132522417013416 00000000000000/* AS path filter list. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "log.h" #include "memory.h" #include "buffer.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_filter.h" /* List of AS filter list. */ struct as_list_list { struct as_list *head; struct as_list *tail; }; /* AS path filter master. */ struct as_list_master { /* List of access_list which name is number. */ struct as_list_list num; /* List of access_list which name is string. */ struct as_list_list str; /* Hook function which is executed when new access_list is added. */ void (*add_hook) (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; }; enum as_list_type { ACCESS_TYPE_STRING, ACCESS_TYPE_NUMBER }; /* AS path filter list. */ struct as_list { char *name; enum as_list_type type; struct as_list *next; struct as_list *prev; struct as_filter *head; struct as_filter *tail; }; /* ip as-path access-list 10 permit AS1. */ static struct as_list_master as_list_master = { {NULL, NULL}, {NULL, NULL}, NULL, NULL }; /* Allocate new AS filter. */ 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); install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd); install_element (ENABLE_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-0.99.22.4/bgpd/bgp_filter.h0000644000175000017500000000233112132522417013425 00000000000000/* 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-0.99.22.4/bgpd/bgp_fsm.c0000644000175000017500000010016312211704467012727 00000000000000/* BGP-4 Finite State Machine From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] Copyright (C) 1996, 97, 98 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "vty.h" #include "sockunion.h" #include "thread.h" #include "log.h" #include "stream.h" #include "memory.h" #include "plist.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_open.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ /* BGP FSM (finite state machine) has three types of functions. Type one is thread functions. Type two is event functions. Type three is FSM functions. Timer functions are set by bgp_timer_set function. */ /* BGP event function. */ int bgp_event (struct thread *); /* BGP thread functions. */ static int bgp_start_timer (struct thread *); static int bgp_connect_timer (struct thread *); static int bgp_holdtime_timer (struct thread *); static int bgp_keepalive_timer (struct thread *); /* BGP FSM functions. */ static int bgp_start (struct peer *); /* BGP start timer jitter. */ static int bgp_start_jitter (int time) { return ((rand () % (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_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case Connect: /* After start timer is expired, the peer moves to Connnect status. Make sure start timer is off and connect timer is on. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); 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_asorig); 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_asorig); 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_asorig); 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); } BGP_TIMER_OFF (peer->t_asorig); 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_asorig); 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 occured, this function change status and reset read/write and timer thread. */ void bgp_fsm_change_status (struct peer *peer, int status) { bgp_dump_state (peer, peer->status, status); /* 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); /* 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_asorig); 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 (orf_name); } /* Reset keepalive and holdtime */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) { peer->v_keepalive = peer->keepalive; peer->v_holdtime = peer->holdtime; } else { peer->v_keepalive = peer->bgp->default_keepalive; peer->v_holdtime = peer->bgp->default_holdtime; } peer->update_time = 0; /* Until we are sure that there is no problem about prefix count this should be commented out.*/ #if 0 /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; #endif /* 0 */ return 0; } /* BGP peer is stoped by the error. */ static int bgp_stop_with_error (struct peer *peer) { /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); 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) { 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); } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) 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; 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; } 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; } /* 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)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Hold timer expire", peer->host); /* Send notify to remote peer. */ bgp_notify_send (peer, BGP_NOTIFY_HOLD_ERR, 0); /* Sweep if it is temporary peer. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); peer_delete (peer); return -1; } /* bgp_stop needs to be invoked while in Established state */ bgp_stop(peer); return 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 */ }, { /* 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 */ }, { /* 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 */ }, { /* 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_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* 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 */ }, { /* 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 */ }, { /* 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 */ }, { /* 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 */ }, }; 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", }; /* 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-0.99.22.4/bgpd/bgp_fsm.h0000644000175000017500000000435512132522417012735 00000000000000/* 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(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(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(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 (master, bgp_event, (P), (E)); \ } while (0) #define BGP_EVENT_FLUSH(P) \ do { \ assert (peer); \ thread_cancel_event (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-0.99.22.4/bgpd/bgp_main.c0000644000175000017500000002544612177450262013102 00000000000000/* 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 "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'}, { "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; /* Master of threads. */ struct thread_master *master; /* 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\ -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 (); 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; extern struct zclient *zclient; extern struct zclient *zlookup; /* 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); /* 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 (iflist, node, nnode, 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); if_delete (ifp); } list_free (iflist); /* 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 bgp_scan_init */ bgp_scan_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); cmd_terminate (); vty_terminate (); if (zclient) zclient_free (zclient); if (zlookup) zclient_free (zlookup); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); /* reverse bgp_master_init */ if (master) thread_master_free (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; struct thread thread; int tmp_port; /* 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: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 '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 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Make thread master. */ master = bm->master; /* Initializations. */ srand (time (NULL)); signal_init (master, array_size(bgp_signals), bgp_signals); zprivs_init (&bgpd_privs); cmd_init (1); vty_init (master); memory_init (); /* BGP related initialization. */ bgp_init (); /* Sort CLI commands. */ sort_node (); /* 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", QUAGGA_VERSION, vty_port, (bm->address ? bm->address : ""), bm->port); /* Start finite state machine, here we go! */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return (0); } quagga-0.99.22.4/bgpd/bgp_mpath.c0000644000175000017500000004731412177450262013265 00000000000000/* $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 "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_mpath.h" /* * 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 && (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; #ifdef HAVE_IPV6 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; #endif /* HAVE_IPV6 */ } } 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, struct bgp_maxpaths_cfg *mpath_cfg) { 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[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN]; 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_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 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; for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { asmerge = aspath_aggregate (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); } } 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; #ifdef HAVE_IPV6 if (attr.extra) memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); #endif /* HAVE_IPV6 */ /* 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-0.99.22.4/bgpd/bgp_mpath.h0000644000175000017500000000567612177450262013277 00000000000000/* $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); /* 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 *, struct bgp_maxpaths_cfg *); 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-0.99.22.4/bgpd/bgp_mplsvpn.c0000644000175000017500000004677012177450262013660 00000000000000/* MPLS-VPN Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "log.h" #include "memory.h" #include "stream.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" 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; } 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_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_vpnv4 (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; int psize; int prefixlen; u_int32_t label; u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; struct prefix_rd prd; u_char *tagpnt; /* Check peer status. */ if (peer->status != Established) return 0; /* Make prefix_rd */ prd.family = AF_UNSPEC; prd.prefixlen = 64; pnt = packet->nlri; lim = pnt + packet->length; for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ prefixlen = *pnt++; p.family = AF_INET; psize = PSIZE (prefixlen); if (prefixlen < 88) { zlog_err ("prefix length is less than 88: %d", prefixlen); return -1; } label = decode_label (pnt); /* Copyr label to prefix. */ tagpnt = pnt;; /* Copy routing distinguisher to rd. */ memcpy (&prd.val, pnt + 3, 8); /* Decode RD type. */ type = decode_rd_type (pnt + 3); /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 5, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 5, &rd_ip); else { zlog_err ("Invalid RD type %d", type); return -1; } p.prefixlen = prefixlen - 88; memcpy (&p.u.prefix, pnt + 11, psize - 11); #if 0 if (type == RD_TYPE_AS) zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val, inet_ntoa (p.u.prefix4), p.prefixlen); else if (type == RD_TYPE_IP) zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip), rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); #endif /* 0 */ if (pnt + psize > lim) return -1; if (attr) bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); else bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; } int str2prefix_rd (const char *str, struct prefix_rd *prd) { int ret; char *p; char *p2; struct stream *s; char *half; struct in_addr addr; s = stream_new (8); prd->family = AF_UNSPEC; prd->prefixlen = 64; p = strchr (str, ':'); if (! p) return 0; if (! all_digit (p + 1)) return 0; half = XMALLOC (MTYPE_TMP, (p - str) + 1); memcpy (half, str, (p - str)); half[p - str] = '\0'; p2 = strchr (str, '.'); if (! p2) { if (! all_digit (half)) { XFREE (MTYPE_TMP, half); return 0; } stream_putw (s, RD_TYPE_AS); stream_putw (s, atoi (half)); stream_putl (s, atol (p + 1)); } else { ret = inet_aton (half, &addr); if (! ret) { XFREE (MTYPE_TMP, half); return 0; } stream_putw (s, RD_TYPE_IP); stream_put_in_addr (s, &addr); stream_putw (s, atol (p + 1)); } memcpy (prd->val, s->data, 8); return 1; } int str2tag (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_IP) { decode_rd_ip (pnt + 2, &rd_ip); snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); return buf; } return NULL; } /* For testing purpose, static route of MPLS-VPN. */ DEFUN (vpnv4_network, vpnv4_network_cmd, "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify Route Distinguisher\n" "VPN Route Distinguisher\n" "BGP tag\n" "tag value\n") { return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]); } /* For testing purpose, static route of MPLS-VPN. */ DEFUN (no_vpnv4_network, no_vpnv4_network_cmd, "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify Route Distinguisher\n" "VPN Route Distinguisher\n" "BGP tag\n" "tag value\n") { return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]); } 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_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_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, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int tags) { struct bgp *bgp; struct bgp_table *table; struct bgp_node *rn; struct bgp_node *rm; struct bgp_info *ri; int rd_header; int header = 1; char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; if ((table = rn->info) != NULL) { rd_header = 1; for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) for (ri = rm->info; ri; ri = ri->next) { if (type == bgp_show_type_neighbor) { union sockunion *su = output_arg; if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) continue; } if (header) { if (tags) vty_out (vty, v4_header_tag, VTY_NEWLINE); else { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, v4_header, VTY_NEWLINE); } header = 0; } if (rd_header) { u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; u_char *pnt; pnt = rn->p.u.val; /* Decode RD type. */ type = decode_rd_type (pnt); /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 2, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 2, &rd_ip); vty_out (vty, "Route Distinguisher: "); if (type == RD_TYPE_AS) vty_out (vty, "%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; } if (tags) route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); else route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); } } } return CMD_SUCCESS; } DEFUN (show_ip_bgp_vpnv4_all, show_ip_bgp_vpnv4_all_cmd, "show ip bgp vpnv4 all", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n") { return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0); } DEFUN (show_ip_bgp_vpnv4_rd, show_ip_bgp_vpnv4_rd_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0); } DEFUN (show_ip_bgp_vpnv4_all_tags, show_ip_bgp_vpnv4_all_tags_cmd, "show ip bgp vpnv4 all tags", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Display BGP tags for prefixes\n") { return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 1); } DEFUN (show_ip_bgp_vpnv4_rd_tags, show_ip_bgp_vpnv4_rd_tags_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1); } DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, show_ip_bgp_vpnv4_all_neighbor_routes_cmd, "show ip bgp vpnv4 all neighbors A.B.C.D routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { union sockunion su; struct peer *peer; 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, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, show_ip_bgp_vpnv4_rd_neighbor_routes_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { int ret; union sockunion su; struct peer *peer; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd, "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { int ret; struct peer *peer; union sockunion su; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return show_adj_route_vpn (vty, peer, NULL); } DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { int ret; struct peer *peer; struct prefix_rd prd; union sockunion su; ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return show_adj_route_vpn (vty, peer, &prd); } void bgp_mplsvpn_init (void) { install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); } quagga-0.99.22.4/bgpd/bgp_mplsvpn.h0000644000175000017500000000263612132522417013647 00000000000000/* 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_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_vpnv4 (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-0.99.22.4/bgpd/bgp_network.c0000644000175000017500000003216712177450262013645 00000000000000/* 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 "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; } /* 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 (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); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); if (! peer1 || peer1->status == Idle) { 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 Idle state", inet_sutop (&su, buf)); } close (bgp_sock); return -1; } /* In case of peer is EBGP, we should set TTL for this connection. */ if (peer1->sort == BGP_PEER_EBGP) { sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl); if (peer1->gtsm_hops) sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops); } /* 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); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); peer->su = su; peer->fd = bgp_sock; peer->status = Active; peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); } 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; 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)); 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", peer->ifname); 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; d = sockunion2hostprefix (dst); 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); } } prefix_free (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) { unsigned int ifindex = 0; /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); if (peer->fd < 0) return -1; /* If we can get socket for the peer, adjest TTL and make connection. */ if (peer->sort == BGP_PEER_EBGP) { sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); if (peer->gtsm_hops) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); } 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); # ifdef HAVE_IPV6 else if (sockunion_family (&peer->su) == AF_INET6) setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); # endif 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); #ifdef HAVE_IPV6 if (peer->ifname) ifindex = if_nametoindex (peer->ifname); #endif /* HAVE_IPV6 */ 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); # ifdef HAVE_IPV6 else if (sa->sa_family == AF_INET6) setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); # endif #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 (master, bgp_accept, listener, sock); listnode_add (bm->listen_sockets, listener); return 0; } /* IPv6 supported version of BGP server socket setup. */ #if defined (HAVE_IPV6) && ! defined (NRL) 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; } #else /* Traditional IPv4 only version. */ int bgp_socket (unsigned short port, const char *address) { int sock; int socklen; struct sockaddr_in sin; int ret, en; sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { zlog_err ("socket: %s", safe_strerror (errno)); return sock; } /* if we intend to implement ttl-security, this socket needs ttl=255 */ sockopt_ttl (AF_INET, sock, MAXTTL); memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons (port); socklen = sizeof (struct sockaddr_in); if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1)) { zlog_err("bgp_socket: could not parse ip address %s: %s", address, safe_strerror (errno)); return ret; } #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.sin_len = socklen; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen); if (ret < 0) { close (sock); return ret; } return sock; } #endif /* HAVE_IPV6 && !NRL */ 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-0.99.22.4/bgpd/bgp_network.h0000644000175000017500000000210412132522417013627 00000000000000/* 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 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 int bgp_md5_set (struct peer *); #endif /* _QUAGGA_BGP_NETWORK_H */ quagga-0.99.22.4/bgpd/bgp_nexthop.c0000644000175000017500000010442412211704467013633 00000000000000/* 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 "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_damp.h" #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ struct bgp_nexthop_cache *zlookup_query (struct in_addr); #ifdef HAVE_IPV6 struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); #endif /* HAVE_IPV6 */ /* Only one BGP scan thread are activated at the same time. */ static struct thread *bgp_scan_thread = NULL; /* BGP import thread */ static struct thread *bgp_import_thread = NULL; /* BGP scan interval. */ static int bgp_scan_interval; /* BGP import interval. */ static int bgp_import_interval; /* Route table for next-hop lookup cache. */ static struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; static struct bgp_table *cache1_table[AFI_MAX]; static struct bgp_table *cache2_table[AFI_MAX]; /* Route table for connected route. */ static struct bgp_table *bgp_connected_table[AFI_MAX]; /* BGP nexthop lookup query client. */ struct zclient *zlookup = NULL; /* Add nexthop to the end of the list. */ static void bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) { struct nexthop *last; for (last = bnc->nexthop; last && last->next; last = last->next) ; if (last) last->next = nexthop; else bnc->nexthop = nexthop; nexthop->prev = last; } static 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); } } static struct bgp_nexthop_cache * bnc_new (void) { return XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); } static void bnc_free (struct bgp_nexthop_cache *bnc) { bnc_nexthop_free (bnc); XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } static int bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) { if (next1->type != next2->type) return 0; switch (next1->type) { case ZEBRA_NEXTHOP_IPV4: if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) return 0; break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4) || next1->ifindex != next2->ifindex) return 0; break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: if (next1->ifindex != next2->ifindex) return 0; break; #ifdef HAVE_IPV6 case ZEBRA_NEXTHOP_IPV6: if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) return 0; break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) return 0; if (next1->ifindex != next2->ifindex) return 0; break; #endif /* HAVE_IPV6 */ default: /* do nothing */ break; } return 1; } static int bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, struct bgp_nexthop_cache *bnc2) { int i; struct nexthop *next1, *next2; if (bnc1->nexthop_num != bnc2->nexthop_num) return 1; next1 = bnc1->nexthop; next2 = bnc2->nexthop; for (i = 0; i < bnc1->nexthop_num; i++) { if (! bgp_nexthop_same (next1, next2)) return 1; next1 = next1->next; next2 = next2->next; } return 0; } /* If nexthop exists on connected network return 1. */ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; /* If zebra is not enabled return */ if (zlookup->sock < 0) return 1; /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop); if (rn) { bgp_unlock_node (rn); return 1; } } #ifdef HAVE_IPV6 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; } } } #endif /* HAVE_IPV6 */ return 0; } #ifdef HAVE_IPV6 /* Check specified next-hop is reachable or not. */ static int bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct attr *attr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } /* Only check IPv6 global address only nexthop. */ attr = ri->attr; if (attr->extra->mp_nexthop_len != 16 || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; p.u.prefix6 = attr->extra->mp_nexthop_global; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) old = cache2_table[AFI_IP6]; else old = cache1_table[AFI_IP6]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get (ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; } #endif /* HAVE_IPV6 */ /* Check specified next-hop is reachable or not. */ int bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct in_addr addr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } #ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); #endif /* HAVE_IPV6 */ addr = ri->attr->nexthop; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = addr; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query (addr))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) old = cache2_table[AFI_IP]; else old = cache1_table[AFI_IP]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get(ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; } /* Reset and free all BGP nexthop cache. */ static void bgp_nexthop_cache_reset (struct bgp_table *table) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { bnc_free (bnc); rn->info = NULL; bgp_unlock_node (rn); } } static void bgp_scan (afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp *bgp; struct bgp_info *bi; struct bgp_info *next; struct peer *peer; struct listnode *node, *nnode; int valid; int current; int changed; int metricchanged; /* Change cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_table[afi] = cache2_table[afi]; else bgp_nexthop_cache_table[afi] = cache1_table[afi]; /* Get default bgp. */ bgp = bgp_get_default (); if (bgp == NULL) return; /* Maximum prefix check */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->status != Established) continue; if (peer->afc[afi][SAFI_UNICAST]) bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1); if (peer->afc[afi][SAFI_MULTICAST]) bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1); if (peer->afc[afi][SAFI_MPLS_VPN]) bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1); } for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next (rn)) { for (bi = rn->info; bi; bi = next) { next = bi->next; if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) { changed = 0; metricchanged = 0; if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1) valid = bgp_nexthop_onlink (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, &changed, &metricchanged); current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; if (changed) SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); else UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); if (valid != current) { if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) { bgp_aggregate_decrement (bgp, &rn->p, bi, afi, SAFI_UNICAST); bgp_info_unset_flag (rn, bi, BGP_INFO_VALID); } else { bgp_info_set_flag (rn, bi, BGP_INFO_VALID); bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } } if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], BGP_CONFIG_DAMPENING) && bi->extra && bi->extra->damp_info ) if (bgp_damp_scan (bi, afi, SAFI_UNICAST)) bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } } bgp_process (bgp, rn, afi, SAFI_UNICAST); } /* Flash old cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_reset (cache2_table[afi]); else bgp_nexthop_cache_reset (cache1_table[afi]); if (BGP_DEBUG (events, EVENTS)) { if (afi == AFI_IP) zlog_debug ("scanning IPv4 Unicast routing tables"); else if (afi == AFI_IP6) zlog_debug ("scanning IPv6 Unicast routing tables"); } /* Reevaluate default-originate route-maps and announce/withdraw * default route if neccesary. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->status == Established && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) && peer->default_rmap[afi][safi].name) bgp_default_originate (peer, afi, safi, 0); } } /* BGP scan thread. This thread check nexthop reachability. */ static int bgp_scan_timer (struct thread *t) { bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("Performing BGP general scanning"); bgp_scan (AFI_IP, SAFI_UNICAST); #ifdef HAVE_IPV6 bgp_scan (AFI_IP6, SAFI_UNICAST); #endif /* HAVE_IPV6 */ 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); } 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); 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); 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; if (addr->family == AF_INET) { PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); 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; } } #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); 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; } } #endif /* HAVE_IPV6 */ } 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; if (addr->family == AF_INET) { PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); 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); } #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); 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); } #endif /* HAVE_IPV6 */ } 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; } static struct bgp_nexthop_cache * zlookup_read (void) { struct stream *s; uint16_t length; u_char marker; u_char version; uint16_t command; int nbytes; struct in_addr raddr; uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } command = stream_getw (s); raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; } struct bgp_nexthop_cache * zlookup_query (struct in_addr addr) { int ret; struct stream *s; /* Check socket. */ if (zlookup->sock < 0) return NULL; s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); 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 ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return NULL; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return NULL; } return zlookup_read (); } #ifdef HAVE_IPV6 static struct bgp_nexthop_cache * zlookup_read_ipv6 (void) { struct stream *s; uint16_t length; u_char version, marker; uint16_t command; int nbytes; struct in6_addr raddr; uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } command = stream_getw (s); stream_get (&raddr, s, 16); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop->gate.ipv6, s, 16); break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: stream_get (&nexthop->gate.ipv6, s, 16); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; } struct bgp_nexthop_cache * zlookup_query_ipv6 (struct in6_addr *addr) { int ret; struct stream *s; /* Check socket. */ if (zlookup->sock < 0) return NULL; s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); stream_put (s, addr, 16); stream_putw_at (s, 0, stream_get_endp (s)); ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return NULL; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return NULL; } return zlookup_read_ipv6 (); } #endif /* HAVE_IPV6 */ static int bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) { struct stream *s; int ret; u_int16_t length, command; u_char version, marker; int nbytes; struct in_addr addr; struct in_addr nexthop; u_int32_t metric = 0; u_char nexthop_num; u_char nexthop_type; /* If lookup connection is not available return valid. */ if (zlookup->sock < 0) { if (igpmetric) *igpmetric = 0; return 1; } /* Send query to the lookup connection */ s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP); stream_putc (s, p->prefixlen); stream_put_in_addr (s, &p->u.prefix4); stream_putw_at (s, 0, stream_get_endp (s)); /* Write the packet. */ ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return 1; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return 1; } /* Get result. */ stream_reset (s); /* Fetch length. */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); /* Fetch whole data. */ nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return 0; } command = stream_getw (s); addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); /* Set IGP metric value. */ if (igpmetric) *igpmetric = metric; /* If there is nexthop then this is active route. */ if (nexthop_num) { nexthop.s_addr = 0; nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); /* ifindex */ (void)stream_getl (s); break; default: /* do nothing */ break; } *igpnexthop = nexthop; return 1; } else return 0; } /* Scan all configured BGP route then check the route exists in IGP or not. */ static int bgp_import (struct thread *t) { struct bgp *bgp; struct bgp_node *rn; struct bgp_static *bgp_static; struct listnode *node, *nnode; int valid; u_int32_t metric; struct in_addr nexthop; afi_t afi; safi_t safi; bgp_import_thread = thread_add_timer (master, bgp_import, NULL, bgp_import_interval); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("Import timer expired."); for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { if (bgp_static->backdoor) continue; valid = bgp_static->valid; metric = bgp_static->igpmetric; nexthop = bgp_static->igpnexthop; if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) && afi == AFI_IP && safi == SAFI_UNICAST) bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric, &bgp_static->igpnexthop); else { bgp_static->valid = 1; bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; } if (bgp_static->valid != valid) { if (bgp_static->valid) bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); else bgp_static_withdraw (bgp, &rn->p, afi, safi); } else if (bgp_static->valid) { if (bgp_static->igpmetric != metric || bgp_static->igpnexthop.s_addr != nexthop.s_addr || bgp_static->rmap.name) bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); } } } return 0; } /* Connect to zebra for nexthop lookup. */ static int zlookup_connect (struct thread *t) { struct zclient *zlookup; zlookup = THREAD_ARG (t); zlookup->t_connect = NULL; if (zlookup->sock != -1) return 0; if (zclient_socket_connect (zlookup) < 0) return -1; return 0; } /* Check specified multiaccess next-hop. */ int bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) { struct bgp_node *rn1; struct bgp_node *rn2; struct prefix p1; struct prefix p2; struct in_addr addr; int ret; ret = inet_aton (peer, &addr); if (! ret) return 0; memset (&p1, 0, sizeof (struct prefix)); p1.family = AF_INET; p1.prefixlen = IPV4_MAX_BITLEN; p1.u.prefix4 = nexthop; memset (&p2, 0, sizeof (struct prefix)); p2.family = AF_INET; p2.prefixlen = IPV4_MAX_BITLEN; p2.u.prefix4 = addr; /* If bgp scan is not enabled, return invalid. */ if (zlookup->sock < 0) return 0; rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); if (! rn1) return 0; bgp_unlock_node (rn1); rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); if (! rn2) return 0; bgp_unlock_node (rn2); /* This is safe, even with above unlocks, since we are just comparing pointers to the objects, not the objects themselves. */ if (rn1 == rn2) return 1; return 0; } DEFUN (bgp_scan_time, bgp_scan_time_cmd, "bgp scan-time <5-60>", "BGP specific commands\n" "Configure background scanner interval\n" "Scanner interval (seconds)\n") { bgp_scan_interval = atoi (argv[0]); if (bgp_scan_thread) { thread_cancel (bgp_scan_thread); bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); } return CMD_SUCCESS; } DEFUN (no_bgp_scan_time, no_bgp_scan_time_cmd, "no bgp scan-time", NO_STR "BGP specific commands\n" "Configure background scanner interval\n") { bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; if (bgp_scan_thread) { thread_cancel (bgp_scan_thread); bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); } return CMD_SUCCESS; } ALIAS (no_bgp_scan_time, no_bgp_scan_time_val_cmd, "no bgp scan-time <5-60>", NO_STR "BGP specific commands\n" "Configure background scanner interval\n" "Scanner interval (seconds)\n") static int show_ip_bgp_scan_tables (struct vty *vty, const char detail) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; char buf[INET6_ADDRSTRLEN]; u_char i; if (bgp_scan_thread) vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); else vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) { vty_out (vty, " %s valid [IGP metric %d]%s", inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) for (i = 0; i < bnc->nexthop_num; i++) switch (bnc->nexthop[i].type) { case NEXTHOP_TYPE_IPV4: vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " gate %s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN)); vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; default: vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); } } else vty_out (vty, " %s invalid%s", inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } #ifdef HAVE_IPV6 { for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) { vty_out (vty, " %s valid [IGP metric %d]%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) for (i = 0; i < bnc->nexthop_num; i++) switch (bnc->nexthop[i].type) { case NEXTHOP_TYPE_IPV6: vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; default: vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); } } else vty_out (vty, " %s invalid%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } } #endif /* HAVE_IPV6 */ vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_connected_table[AFI_IP]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); #ifdef HAVE_IPV6 { for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) vty_out (vty, " %s/%d%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), rn->p.prefixlen, VTY_NEWLINE); } #endif /* HAVE_IPV6 */ return CMD_SUCCESS; } DEFUN (show_ip_bgp_scan, show_ip_bgp_scan_cmd, "show ip bgp scan", SHOW_STR IP_STR BGP_STR "BGP scan status\n") { return show_ip_bgp_scan_tables (vty, 0); } DEFUN (show_ip_bgp_scan_detail, show_ip_bgp_scan_detail_cmd, "show ip bgp scan detail", SHOW_STR IP_STR BGP_STR "BGP scan status\n" "More detailed output\n") { return show_ip_bgp_scan_tables (vty, 1); } int bgp_config_write_scan_time (struct vty *vty) { if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT) vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE); return CMD_SUCCESS; } void bgp_scan_init (void) { zlookup = zclient_new (); zlookup->sock = -1; zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); cache2_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); #ifdef HAVE_IPV6 cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); cache2_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); #endif /* HAVE_IPV6 */ /* Make BGP scan thread. */ bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); /* Make BGP import there. */ bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0); install_element (BGP_NODE, &bgp_scan_time_cmd); install_element (BGP_NODE, &no_bgp_scan_time_cmd); install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd); } void bgp_scan_finish (void) { /* Only the current one needs to be reset. */ bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]); bgp_table_unlock (cache1_table[AFI_IP]); cache1_table[AFI_IP] = NULL; bgp_table_unlock (cache2_table[AFI_IP]); cache2_table[AFI_IP] = NULL; bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; #ifdef HAVE_IPV6 /* Only the current one needs to be reset. */ bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]); bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; bgp_table_unlock (cache2_table[AFI_IP6]); cache2_table[AFI_IP6] = NULL; bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; #endif /* HAVE_IPV6 */ } quagga-0.99.22.4/bgpd/bgp_nexthop.h0000644000175000017500000000350712177450262013642 00000000000000/* 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" #define BGP_SCAN_INTERVAL_DEFAULT 60 #define BGP_IMPORT_INTERVAL_DEFAULT 15 /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { /* This nexthop exists in IGP. */ u_char valid; /* Nexthop is changed. */ u_char changed; /* Nexthop is changed. */ u_char metricchanged; /* IGP route's metric. */ u_int32_t metric; /* Nexthop number and nexthop linked list.*/ u_char nexthop_num; struct nexthop *nexthop; }; extern void bgp_scan_init (void); extern void bgp_scan_finish (void); 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, char *); 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); #endif /* _QUAGGA_BGP_NEXTHOP_H */ quagga-0.99.22.4/bgpd/bgp_open.c0000644000175000017500000007474612177450262013126 00000000000000/* 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 "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; 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) { mpc->afi = stream_getw (s); 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: #ifdef HAVE_IPV6 case AFI_IP6: #endif 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: return 1; } } 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 (sizeof (struct capability_orf_entry) + (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_CEASE, 0); 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; int restart_bit = 0; 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)) restart_bit = 1; 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, restart_bit ? " " : " 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] = sizeof (struct capability_mp_data), [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry), [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr), [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] = sizeof (struct capability_orf_entry), }; /** * 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_CEASE, 0); 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_CEASE, 0); 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_CEASE, 0); 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_CEASE, 0); 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_CEASE, 0); 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_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) { 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; afi_t afi; safi_t safi; as_t local_as; /* 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); } #ifdef HAVE_IPV6 /* IPv6 unicast. */ if (peer->afc[AFI_IP6][SAFI_UNICAST]) { peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP6); stream_putc (s, 0); stream_putc (s, SAFI_UNICAST); } /* IPv6 multicast. */ if (peer->afc[AFI_IP6][SAFI_MULTICAST]) { peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP6); stream_putc (s, 0); stream_putc (s, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ /* Route refresh. */ SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); stream_putc (s, CAPABILITY_CODE_REFRESH_OLD); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); stream_putc (s, CAPABILITY_CODE_REFRESH); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); /* 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); } /* Graceful restart capability */ if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) { SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2); stream_putc (s, CAPABILITY_CODE_RESTART); stream_putc (s, CAPABILITY_CODE_RESTART_LEN); stream_putw (s, peer->bgp->restart_time); } /* Total Opt Parm Len. */ len = stream_get_endp (s) - cp - 1; stream_putc_at (s, cp, len); } quagga-0.99.22.4/bgpd/bgp_open.h0000644000175000017500000000625112132522417013106 00000000000000/* 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 /* 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-0.99.22.4/bgpd/bgp_packet.c0000644000175000017500000021252512211704467013417 00000000000000/* BGP packet management routine. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "stream.h" #include "network.h" #include "prefix.h" #include "command.h" #include "log.h" #include "memory.h" #include "sockunion.h" /* for inet_ntop () */ #include "linklist.h" #include "plist.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" int stream_put_prefix (struct stream *, struct prefix *); /* Set up BGP packet marker and packet type. */ static int bgp_packet_set_marker (struct stream *s, u_char type) { int i; /* Fill in marker. */ for (i = 0; i < BGP_MARKER_SIZE; i++) stream_putc (s, 0xff); /* Dummy total length. This field is should be filled in later on. */ stream_putw (s, 0); /* BGP packet type. */ stream_putc (s, type); /* Return current stream size. */ return stream_get_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 bgp_adj_out *adj; struct bgp_advertise *adv; struct stream *packet; struct bgp_node *rn = NULL; struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; unsigned long pos; s = peer->work; stream_reset (s); 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; /* When remaining space can't include NLRI and it's length. */ if (STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) 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; } bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); pos = stream_get_endp (s); stream_putw (s, 0); total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, &rn->p, afi, safi, from, prd, tag); stream_putw_at (s, pos, total_attr_len); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); if (BGP_DEBUG (update, UPDATE_OUT)) { 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 (! (afi == AFI_IP && safi == SAFI_UNICAST)) break; } if (! stream_empty (s)) { bgp_packet_set_size (s); packet = stream_dup (s); bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); stream_reset (s); return packet; } return NULL; } static struct stream * bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *packet; 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); packet = stream_dup (s); bgp_packet_add (peer, packet); stream_free (s); return packet; } /* Make BGP withdraw packet. */ 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; unsigned long pos; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; s = peer->work; stream_reset (s); while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { assert (adv->rn); adj = adv->adj; rn = adv->rn; if (STREAM_REMAIN (s) < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) break; if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { struct prefix_rd *prd = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; pos = stream_get_endp (s); stream_putw (s, 0); total_attr_len = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL); /* Set total path attribute length. */ stream_putw_at (s, pos, total_attr_len); } if (BGP_DEBUG (update, UPDATE_OUT)) { 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 (! (afi == AFI_IP && safi == SAFI_UNICAST)) break; } 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); } 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 stream *packet; 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); #ifdef HAVE_IPV6 else str2prefix ("::/0", &p); #endif /* HAVE_IPV6 */ /* 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); packet = stream_dup (s); stream_free (s); /* Dump packet if debug option is set. */ #ifdef DEBUG /* bgp_packet_dump (packet); */ #endif /* DEBUG */ /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } void bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *packet; struct prefix p; unsigned long pos; unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; if (DISABLE_BGP_ANNOUNCE) return; if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); #ifdef HAVE_IPV6 else str2prefix ("::/0", &p); #endif /* HAVE_IPV6 */ total_attr_len = 0; pos = 0; if (BGP_DEBUG (update, UPDATE_OUT)) { 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 { pos = stream_get_endp (s); stream_putw (s, 0); total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); /* Set total path attribute length. */ stream_putw_at (s, pos, total_attr_len); } bgp_packet_set_size (s); packet = stream_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Get next packet to be written. */ 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 = FIFO_HEAD (&peer->sync[afi][safi]->withdraw); if (adv) { s = bgp_withdraw_packet (peer, afi, safi); if (s) return s; } } for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { adv = FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) { if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) && safi != SAFI_MPLS_VPN) { if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) s = bgp_update_packet (peer, afi, safi); } else s = bgp_update_packet (peer, afi, safi); } if (s) return s; } if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) { if (peer->afc_nego[afi][safi] && peer->synctime && ! 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 = 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++; /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); /* Flush any existing events */ BGP_EVENT_ADD (peer, BGP_Stop); 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); /* Put socket in blocking mode. */ val = fcntl (peer->fd, F_GETFL, 0); fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK); /* Stop collecting data within the socket */ sockopt_cork (peer->fd, 0); ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); 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++; /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); BGP_EVENT_ADD (peer, BGP_Stop); 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); } 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: User reset", peer->host); } else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) { peer->last_reset = PEER_DOWN_USER_SHUTDOWN; zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); } else { peer->last_reset = PEER_DOWN_NOTIFY_SEND; zlog_info ("Notification sent to neighbor %s: type %u/%u", peer->host, code, sub_code); } } else zlog_info ("Notification sent to neighbor %s: configuration change", peer->host); /* 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; struct stream *packet; 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); } /* Make real packet. */ packet = stream_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Send capability message to the peer. */ void bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, int capability_code, int action) { struct stream *s; struct stream *packet; int length; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = 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); /* Make real packet. */ packet = stream_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); 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)) { /* Under OpenConfirm status, local peer structure already hold remote router ID. */ if (peer != new && (peer->status == OpenConfirm || peer->status == OpenSent) && sockunion_same (&peer->su, &new->su)) { /* 1. The BGP Identifier of the local system is compared to the BGP Identifier of the remote system (as specified in the OPEN message). */ if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) { /* 2. If the value of the local BGP Identifier is less than the remote one, the local system closes BGP connection that already exists (the one that is already in the OpenConfirm state), and accepts BGP connection initiated by the remote system. */ if (peer->fd >= 0) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return 1; } else { /* 3. Otherwise, the local system closes newly created BGP connection (the one associated with the newly received OPEN message), and continues to use the existing one (the one that is already in the OpenConfirm state). */ if (new->fd >= 0) bgp_notify_send (new, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } } } 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", peer->host, version, remote_as, holdtime, inet_ntoa (remote_id)); /* 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; /* Hack part. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (realpeer->status == Established && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE)) { realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT); } else if (ret == 0 && realpeer->status != Active && realpeer->status != OpenSent && realpeer->status != OpenConfirm && realpeer->status != Connect) { /* XXX: This is an awful problem.. * * According to the RFC we should just let this connection (of the * accepted 'peer') continue on to Established if the other * connection (the 'realpeer' one) is in state Connect, and deal * with the more larval FSM as/when it gets far enough to receive * an Open. We don't do that though, we instead close the (more * developed) accepted connection. * * This means there's a race, which if hit, can loop: * * FSM for A FSM for B * realpeer accept-peer realpeer accept-peer * * Connect Connect * Active * OpenSent OpenSent * * Idle Active * OpenSent OpenSent * * Idle * * Connect Connect * * * If both sides are Quagga, they're almost certain to wait for * the same amount of time of course (which doesn't preclude other * implementations also waiting for same time). The race is * exacerbated by high-latency (in bgpd and/or the network). * * The reason we do this is because our FSM is tied to our peer * structure, which carries our configuration information, etc. * I.e. we can't let the accepted-peer FSM continue on as it is, * cause it's not associated with any actual peer configuration - * it's just a dummy. * * It's possible we could hack-fix this by just bgp_stop'ing the * realpeer and continueing on with the 'transfer FSM' below. * Ideally, we need to seperate FSMs from struct peer. * * Setting one side to passive avoids the race, as a workaround. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s peer status is %s close connection", realpeer->host, LOOKUP (bgp_status_msg, realpeer->status)); bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_REJECT); return -1; } if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)", peer->host, 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 status. */ realpeer->status = peer->status; bgp_stop (peer); /* peer pointer change. Open packet send to neighbor. */ peer = realpeer; bgp_open_send (peer); if (peer->fd < 0) { zlog_err ("bgp_open_receive peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); } /* remote router-id check. */ if (remote_id.s_addr == 0 || 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) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); return -1; } /* From the rfc: A reasonable maximum time between KEEPALIVE messages would be one third of the Hold Time interval. KEEPALIVE messages MUST NOT be sent more frequently than one per second. An implementation MAY adjust the rate at which it sends KEEPALIVE messages as a function of the Hold Time interval. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) send_holdtime = peer->holdtime; else send_holdtime = peer->bgp->default_holdtime; if (holdtime < send_holdtime) peer->v_holdtime = holdtime; else peer->v_holdtime = send_holdtime; peer->v_keepalive = peer->v_holdtime / 3; /* Open option part parse. */ 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_UNACEP_HOLDTIME); 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); BGP_EVENT_ADD (peer, Receive_OPEN_message); peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); return 0; } /* Parse BGP Update packet and make attribute object. */ static int bgp_update_receive (struct peer *peer, bgp_size_t size) { int 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; struct bgp_nlri update; struct bgp_nlri withdraw; struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; /* 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 (&update, 0, sizeof (struct bgp_nlri)); memset (&withdraw, 0, sizeof (struct bgp_nlri)); memset (&mp_update, 0, sizeof (struct bgp_nlri)); memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); 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) { ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); if (ret < 0) return -1; if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); withdraw.afi = AFI_IP; withdraw.safi = SAFI_UNICAST; withdraw.nlri = stream_pnt (s); withdraw.length = withdraw_len; stream_forward_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, &mp_update, &mp_withdraw); if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) 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) { /* Check NLRI packet format and prefix length. */ ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); if (ret < 0) { bgp_attr_unintern_sub (&attr); return -1; } /* Set NLRI portion to structure. */ update.afi = AFI_IP; update.safi = SAFI_UNICAST; update.nlri = stream_pnt (s); update.length = update_len; stream_forward_getp (s, update_len); } /* NLRI is processed only when the peer is configured specific Address Family and Subsequent Address Family. */ if (peer->afc[AFI_IP][SAFI_UNICAST]) { if (withdraw.length) bgp_nlri_parse (peer, NULL, &withdraw); if (update.length) { /* We check well-known attribute only for IPv4 unicast update. */ ret = bgp_attr_check (peer, &attr); if (ret < 0) { bgp_attr_unintern_sub (&attr); return -1; } bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); } if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! attribute_len && ! withdraw_len) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[AFI_IP][SAFI_UNICAST]) bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s", peer->host); } } if (peer->afc[AFI_IP][SAFI_MULTICAST]) { if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST && mp_withdraw.length == 0) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[AFI_IP][SAFI_MULTICAST]) bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s", peer->host); } } if (peer->afc[AFI_IP6][SAFI_UNICAST]) { if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST && mp_withdraw.length == 0) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[AFI_IP6][SAFI_UNICAST]) bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s", peer->host); } } if (peer->afc[AFI_IP6][SAFI_MULTICAST]) { if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_MULTICAST && mp_withdraw.length == 0) { /* End-of-RIB received */ /* NSF delete stale route */ if (peer->nsf[AFI_IP6][SAFI_MULTICAST]) bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST); if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s", peer->host); } } if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) { if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN && mp_withdraw.length == 0) { /* End-of-RIB received */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", peer->host); } } /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&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); } /* 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; u_char reserved; struct stream *s; /* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) { plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return; } /* Status must be Established. */ if (peer->status != Established) { plog_err (peer->log, "%s [Error] Route refresh packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return; } s = peer->ibuf; /* Parse packet. */ afi = stream_getw (s); reserved = stream_getc (s); safi = stream_getc (s); if (BGP_DEBUG (normal, NORMAL)) zlog_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) { u_char *p_pnt = stream_pnt (s); u_char *p_end = stream_pnt (s) + orf_len; struct orf_prefix orfp; u_char common = 0; u_int32_t seq; int psize; char name[BUFSIZ]; 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 (name); break; } ok = ((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 || (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 (name); break; } } peer->orf_plist[afi][safi] = prefix_list_lookup (AFI_ORF_PREFIX, 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; struct bgp *bgp; afi_t afi; safi_t safi; bgp = peer->bgp; end = pnt + length; while (pnt < end) { /* We need at least action, capability code and capability length. */ if (pnt + 3 > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } action = *pnt; 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); } pnt += hdr->length + 3; } 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 occured. */ 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-0.99.22.4/bgpd/bgp_packet.h0000644000175000017500000000414212132522417013411 00000000000000/* 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); #endif /* _QUAGGA_BGP_PACKET_H */ quagga-0.99.22.4/bgpd/bgp_regex.c0000644000175000017500000000420212132522417013244 00000000000000/* AS regular expression routine Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "command.h" #include "memory.h" #include "bgpd.h" #include "bgp_aspath.h" #include "bgp_regex.h" /* Character `_' has special mean. It represents [,{}() ] and the beginning of the line(^) and the end of the line ($). (^|[,{}() ]|$) */ regex_t * bgp_regcomp (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-0.99.22.4/bgpd/bgp_regex.h0000644000175000017500000000233712000052240013242 00000000000000/* 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-0.99.22.4/bgpd/bgp_route.c0000644000175000017500000144472712177450262013324 00000000000000/* BGP routing information Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "linklist.h" #include "memory.h" #include "command.h" #include "stream.h" #include "filter.h" #include "str.h" #include "log.h" #include "routemap.h" #include "buffer.h" #include "sockunion.h" #include "plist.h" #include "thread.h" #include "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_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" /* 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) { 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) 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; } /* Allocate new bgp info structure. */ static struct bgp_info * bgp_info_new (void) { return XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); } /* Free bgp route information. */ static void bgp_info_free (struct bgp_info *binfo) { if (binfo->attr) bgp_attr_unintern (&binfo->attr); 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_HOLDDOWN (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_HOLDDOWN (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 useability state */ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) 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 useability state */ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) 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. br is preferable then return 1. */ static int bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, int *paths_eq) { 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; *paths_eq = 0; /* 0. Null check. */ if (new == NULL) return 0; 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 0; /* 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 0; /* 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 0; /* 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 0; } else { int newhops = aspath_count_hops (newattr->aspath); if (newhops < exist_hops) return 1; if (newhops > exist_hops) return 0; } } /* 5. Origin check. */ if (newattr->origin < existattr->origin) return 1; if (newattr->origin > existattr->origin) return 0; /* 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 0; } /* 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 0; /* 8. IGP metric check. */ newm = existm = 0; if (new->extra) newm = new->extra->igpmetric; if (exist->extra) existm = exist->extra->igpmetric; if (newm < existm) ret = 1; if (newm > existm) ret = 0; /* 9. Maximum path check. */ if (newm == existm) { if (new->peer->sort == BGP_PEER_IBGP) { if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) *paths_eq = 1; } else if (new->peer->as == exist->peer->as) *paths_eq = 1; } else { /* * TODO: If unequal cost ibgp multipath is enabled we can * mark the paths as equal here instead of returning */ return ret; } /* 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 0; } /* 11. Rourter-ID comparision. */ 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 0; /* 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 0; /* 13. Neighbor address comparision. */ ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); if (ret == 1) return 0; if (ret == -1) return 1; return 1; } 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) { /* Free newly generated AS path and community by route-map. */ bgp_attr_flush (attr); 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; /* If peer's id and route's nexthop are same. draft-ietf-idr-bgp4-23 5.1.3 */ if (p->family == AF_INET && IPV4_ADDR_SAME(&peer->remote_id, &riattr->nexthop)) return 0; #ifdef HAVE_IPV6 if (p->family == AF_INET6 && IPV6_ADDR_SAME(&peer->remote_id, &riattr->nexthop)) return 0; #endif /* 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; #ifdef HAVE_IPV6 else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; #endif /* HAVE_IPV6 */ } /* Transparency check. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) transparent = 1; else transparent = 0; /* If community is not disabled check the no-export and local. */ if (! transparent && bgp_community_filter (peer, 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; } #endif /* BGP_SEND_ASPATH_CHECK */ /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { if (aspath_loop_check(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; } } /* 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; } /* 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)); } /* next-hop-set */ if (transparent || reflect || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && ((p->family == AF_INET && attr->nexthop.s_addr) #ifdef HAVE_IPV6 || (p->family == AF_INET6 && ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ ))) { /* NEXT-HOP Unchanged. */ } else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) || (p->family == AF_INET && attr->nexthop.s_addr == 0) #ifdef HAVE_IPV6 || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ || (peer->sort == BGP_PEER_EBGP && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) { /* Set IPv4 nexthop. */ if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) memcpy (&attr->extra->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN); else memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); } #ifdef HAVE_IPV6 /* Set IPv6 nexthop. */ if (p->family == AF_INET6) { /* IPv6 global nexthop must be included. */ memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { /* 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; } } #endif /* HAVE_IPV6 */ /* 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. */ if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) { 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; #ifdef HAVE_IPV6 else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; #endif /* HAVE_IPV6 */ } /* 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) #ifdef HAVE_IPV6 || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ ) { /* Set IPv4 nexthop. */ if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); else memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); } #ifdef HAVE_IPV6 /* 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; } #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 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; } } #endif /* HAVE_IPV6 */ /* 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_maxpaths_cfg *mpath_cfg, struct bgp_info_pair *result) { 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 paths_eq, do_mpath; struct list mp_list; bgp_mp_list_init (&mp_list); do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS || mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS); /* bgp deterministic-med */ new_select = NULL; if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) for (ri1 = rn->info; ri1; ri1 = ri1->next) { if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK)) continue; if (BGP_INFO_HOLDDOWN (ri1)) continue; new_select = ri1; if (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 (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 (bgp_info_cmp (bgp, ri2, new_select, &paths_eq)) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; if (do_mpath && !paths_eq) { bgp_mp_list_clear (&mp_list); bgp_mp_list_add (&mp_list, ri2); } } if (do_mpath && paths_eq) 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, mpath_cfg); 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 (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 (bgp_info_cmp (bgp, ri, new_select, &paths_eq)) { if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (new_select); new_select = ri; if (do_mpath && !paths_eq) { bgp_mp_list_clear (&mp_list); bgp_mp_list_add (&mp_list, ri); } } else if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (ri); if (do_mpath && paths_eq) 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, mpath_cfg); 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; 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; } 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, &bgp->maxpaths[afi][safi], &old_and_new); 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, &bgp->maxpaths[afi][safi], &old_and_new); old_select = old_and_new.old; new_select = old_and_new.new; /* Nothing to do. */ if (old_select && old_select == new_select) { if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) || 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 (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, it 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; memcpy (bm->process_rsclient_queue, bm->process_main_queue, sizeof (struct work_queue *)); bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient; } 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 ( (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) { 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 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) > 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 (&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)) { bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); 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); 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); } /* Make new BGP info. */ new = bgp_info_new (); new->type = type; new->sub_type = sub_type; new->peer = peer; new->attr = attr_new; new->uptime = bgp_clock (); /* 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); 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]; 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. */ if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "route-map;"; goto filtered; } /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) { /* If the peer is EBGP and nexthop is not on connected route, discard it. */ if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! bgp_nexthop_onlink (afi, &new_attr) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { reason = "non-connected next-hop;"; goto filtered; } /* Next hop must not be 0.0.0.0 nor Class 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;"; 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)) { bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); 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); 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); /* 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 && (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } else bgp_info_set_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); 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 = bgp_info_new (); new->type = type; new->sub_type = sub_type; new->peer = peer; new->attr = attr_new; new->uptime = bgp_clock (); /* 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 && (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else 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); /* 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); 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; /* 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 node. */ rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* If peer is soft reconfiguration enabled. Record input packet for further calculation. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && peer != bgp->peer_self) bgp_adj_in_unset (rn, peer); /* Lookup withdrawn route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) break; /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi); 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); #ifdef HAVE_IPV6 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; } } #endif /* HAVE_IPV6 */ 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; if (! table) table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; if (safi != SAFI_MPLS_VPN && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) bgp_default_originate (peer, afi, safi, 0); /* 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); } } void bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_table *table; if (peer->status != Established) return; if (! peer->afc_nego[afi][safi]) return; /* First update is deferred until ORF or ROUTE-REFRESH is received */ if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) return; if (safi != SAFI_MPLS_VPN) bgp_announce_table (peer, afi, safi, NULL, 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) 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) 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. */ 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) 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: bgp_clear_route_table (peer, afi, safi, NULL, peer, purpose); break; default: assert (0); break; } /* If no routes were cleared, nothing was added to workqueue, the * completion function won't be run by workqueue code - call it here. * XXX: Actually, this assumption doesn't hold, see * bgp_clear_route_table(), we queue all non-empty nodes. * * Additionally, there is a presumption in FSM that clearing is only * really needed if peer state is Established - peers in * pre-Established states shouldn't have any route-update state * associated with them (in or out). * * We still can get here in pre-Established though, through * peer_delete -> bgp_fsm_change_status, so this is a useful sanity * check to ensure the assumption above holds. * * At some future point, this check could be move to the top of the * function, and do a quick early-return when state is * pre-Established, avoiding above list and table scans. Once we're * sure it is safe.. */ if (!peer->clear_node_queue->thread) bgp_clear_node_complete (peer->clear_node_queue); } 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); } void bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_table *table; struct bgp_node *rn; struct bgp_adj_in *ain; table = peer->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ain = rn->adj_in; ain ; ain = ain->next) if (ain->peer == peer) { bgp_adj_in_remove (rn, ain); bgp_unlock_node (rn); break; } } void bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; struct bgp_table *table; table = peer->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer) { if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) bgp_rib_remove (rn, ri, peer, afi, safi); break; } } } /* Delete all kernel routes. */ void bgp_cleanup_routes (void) { struct bgp *bgp; struct listnode *node, *nnode; struct bgp_node *rn; struct bgp_table *table; struct bgp_info *ri; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { table = bgp->rib[AFI_IP][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); table = bgp->rib[AFI_IP6][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); } } 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 (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; int psize; int ret; /* Check peer status. */ if (peer->status != Established) return 0; pnt = packet->nlri; lim = pnt + packet->length; for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ p.prefixlen = *pnt++; p.family = afi2family (packet->afi); /* Already checked in nlri_sanity_check(). We do double check here. */ if ((packet->afi == AFI_IP && p.prefixlen > 32) || (packet->afi == AFI_IP6 && p.prefixlen > 128)) return -1; /* Packet size overflow check. */ psize = PSIZE (p.prefixlen); /* When packet overflow occur return immediately. */ if (pnt + psize > lim) return -1; /* Fetch prefix from NLRI packet. */ memcpy (&p.u.prefix, pnt, psize); /* Check address. */ if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST) { if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) { /* * From draft-ietf-idr-bgp4-22, Section 6.3: * If a BGP router receives an UPDATE message with a * semantically incorrect NLRI field, in which a prefix is * semantically incorrect (eg. an unexpected multicast IP * address), it should ignore the prefix. */ zlog (peer->log, LOG_ERR, "IPv4 unicast NLRI is multicast address %s", inet_ntoa (p.u.prefix4)); return -1; } } #ifdef HAVE_IPV6 /* Check address. */ if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST) { if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { char buf[BUFSIZ]; zlog (peer->log, LOG_WARNING, "IPv6 link-local NLRI received %s ignore this NLRI", inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); continue; } } #endif /* HAVE_IPV6 */ /* Normal process. */ if (attr) ret = bgp_update (peer, &p, attr, packet->afi, packet->safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0); else ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); /* Address family configuration mismatch or maximum-prefix count overflow. */ if (ret < 0) return -1; } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; } /* NLRI encode syntax check routine. */ int bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, bgp_size_t length) { u_char *end; u_char prefixlen; int psize; end = pnt + length; /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for syntactic validity. If the field is syntactically incorrect, then the Error Subcode is set to Invalid Network Field. */ while (pnt < end) { prefixlen = *pnt++; /* Prefix length check. */ if ((afi == AFI_IP && prefixlen > 32) || (afi == AFI_IP6 && prefixlen > 128)) { plog_err (peer->log, "%s [Error] Update packet error (wrong prefix length %d)", peer->host, prefixlen); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } /* Packet size overflow check. */ psize = PSIZE (prefixlen); if (pnt + psize > end) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix data overflow prefix size is %d)", peer->host, psize); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } pnt += psize; } /* Packet length consistency check. */ if (pnt != end) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix length mismatch with total length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } return 0; } 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 (); /* 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 = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_STATIC; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = attr_new; new->uptime = bgp_clock (); /* 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 (); /* 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 = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_STATIC; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = attr_new; new->uptime = bgp_clock (); /* 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); } } static void bgp_static_update_vpnv4 (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 *new; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* Make new BGP info. */ new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_STATIC; new->peer = bgp->peer_self; new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP); SET_FLAG (new->flags, BGP_INFO_VALID); new->uptime = bgp_clock (); new->extra = bgp_info_extra_new(); memcpy (new->extra->tag, 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); } void bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; rn = bgp_afi_node_get (bgp->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_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); } 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); } } static void bgp_static_withdraw_vpnv4 (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); } /* 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; } #ifdef HAVE_IPV6 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { vty_out (vty, "%% Malformed prefix (link-local address)%s", VTY_NEWLINE); return CMD_WARNING; } #endif /* HAVE_IPV6 */ apply_mask (&p); /* Set BGP static route configuration. */ rn = bgp_node_get (bgp->route[afi][safi], &p); if (rn->info) { /* Configuration change. */ bgp_static = rn->info; /* Check previous routes are installed into BGP. */ if (bgp_static->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; } /* If BGP scan is not enabled, we should install this route here. */ if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { bgp_static->valid = 1; if (need_update) bgp_static_withdraw (bgp, &p, afi, safi); if (! bgp_static->backdoor) bgp_static_update (bgp, &p, bgp_static, afi, safi); } return CMD_SUCCESS; } /* Configure static BGP network. */ 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; } #ifdef HAVE_IPV6 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { vty_out (vty, "%% Malformed prefix (link-local address)%s", VTY_NEWLINE); return CMD_WARNING; } #endif /* HAVE_IPV6 */ apply_mask (&p); rn = bgp_node_lookup (bgp->route[afi][safi], &p); if (! rn) { vty_out (vty, "%% Can't find specified static route configuration.%s", VTY_NEWLINE); return CMD_WARNING; } bgp_static = rn->info; /* Update BGP RIB. */ if (! bgp_static->backdoor) bgp_static_withdraw (bgp, &p, afi, safi); /* Clear configuration. */ bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); bgp_unlock_node (rn); return CMD_SUCCESS; } /* Called from bgp_delete(). Delete all static routes from the BGP instance. */ void bgp_static_delete (struct bgp *bgp) { afi_t afi; safi_t safi; struct bgp_node *rn; struct bgp_node *rm; struct bgp_table *table; struct bgp_static *bgp_static; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) { if (safi == SAFI_MPLS_VPN) { table = rn->info; for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) { bgp_static = rn->info; bgp_static_withdraw_vpnv4 (bgp, &rm->p, AFI_IP, SAFI_MPLS_VPN, (struct prefix_rd *)&rn->p, bgp_static->tag); bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); } } else { bgp_static = rn->info; bgp_static_withdraw (bgp, &rn->p, afi, safi); bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); } } } int bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, const char *tag_str) { int ret; struct prefix p; struct prefix_rd prd; struct bgp *bgp; struct bgp_node *prn; struct bgp_node *rn; struct bgp_table *table; struct bgp_static *bgp_static; u_char tag[3]; bgp = vty->index; ret = str2prefix (ip_str, &p); if (! ret) { vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask (&p); ret = str2prefix_rd (rd_str, &prd); if (! ret) { vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2tag (tag_str, tag); if (! ret) { vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); return CMD_WARNING; } prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], (struct prefix *)&prd); if (prn->info == NULL) prn->info = bgp_table_init (AFI_IP, SAFI_MPLS_VPN); else bgp_unlock_node (prn); table = prn->info; rn = bgp_node_get (table, &p); if (rn->info) { vty_out (vty, "%% Same network configuration exists%s", VTY_NEWLINE); bgp_unlock_node (rn); } else { /* New configuration. */ bgp_static = bgp_static_new (); bgp_static->valid = 1; memcpy (bgp_static->tag, tag, 3); rn->info = bgp_static; bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); } return CMD_SUCCESS; } /* Configure static BGP network. */ int bgp_static_unset_vpnv4 (struct vty *vty, 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_MPLS_VPN], (struct prefix *)&prd); if (prn->info == NULL) prn->info = bgp_table_init (AFI_IP, SAFI_MPLS_VPN); else bgp_unlock_node (prn); table = prn->info; rn = bgp_node_lookup (table, &p); if (rn) { bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); bgp_static = rn->info; bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); bgp_unlock_node (rn); } else vty_out (vty, "%% Can't find the route%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (bgp_network, bgp_network_cmd, "network A.B.C.D/M", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP, bgp_node_safi (vty), NULL, 0); } DEFUN (bgp_network_route_map, bgp_network_route_map_cmd, "network A.B.C.D/M route-map WORD", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Route-map to modify the attributes\n" "Name of the route map\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP, bgp_node_safi (vty), argv[1], 0); } DEFUN (bgp_network_backdoor, bgp_network_backdoor_cmd, "network A.B.C.D/M backdoor", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (bgp_network_mask, bgp_network_mask_cmd, "network A.B.C.D mask A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), NULL, 0); } DEFUN (bgp_network_mask_route_map, bgp_network_mask_route_map_cmd, "network A.B.C.D mask A.B.C.D route-map WORD", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Route-map to modify the attributes\n" "Name of the route map\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), argv[2], 0); } DEFUN (bgp_network_mask_backdoor, bgp_network_mask_backdoor_cmd, "network A.B.C.D mask A.B.C.D backdoor", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (bgp_network_mask_natural, bgp_network_mask_natural_cmd, "network A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), NULL, 0); } DEFUN (bgp_network_mask_natural_route_map, bgp_network_mask_natural_route_map_cmd, "network A.B.C.D route-map WORD", "Specify a network to announce via BGP\n" "Network number\n" "Route-map to modify the attributes\n" "Name of the route map\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), argv[1], 0); } DEFUN (bgp_network_mask_natural_backdoor, bgp_network_mask_natural_backdoor_cmd, "network A.B.C.D backdoor", "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (no_bgp_network, no_bgp_network_cmd, "no network A.B.C.D/M", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_static_unset (vty, vty->index, argv[0], AFI_IP, bgp_node_safi (vty)); } ALIAS (no_bgp_network, no_bgp_network_route_map_cmd, "no network A.B.C.D/M route-map WORD", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (no_bgp_network, no_bgp_network_backdoor_cmd, "no network A.B.C.D/M backdoor", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") DEFUN (no_bgp_network_mask, no_bgp_network_mask_cmd, "no network A.B.C.D mask A.B.C.D", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty)); } ALIAS (no_bgp_network_mask, no_bgp_network_mask_route_map_cmd, "no network A.B.C.D mask A.B.C.D route-map WORD", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (no_bgp_network_mask, no_bgp_network_mask_backdoor_cmd, "no network A.B.C.D mask A.B.C.D backdoor", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n") DEFUN (no_bgp_network_mask_natural, no_bgp_network_mask_natural_cmd, "no network A.B.C.D", NO_STR "Specify a network to announce via BGP\n" "Network number\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty)); } ALIAS (no_bgp_network_mask_natural, no_bgp_network_mask_natural_route_map_cmd, "no network A.B.C.D route-map WORD", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (no_bgp_network_mask_natural, no_bgp_network_mask_natural_backdoor_cmd, "no network A.B.C.D backdoor", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n") #ifdef HAVE_IPV6 DEFUN (ipv6_bgp_network, ipv6_bgp_network_cmd, "network X:X::X:X/M", "Specify a network to announce via BGP\n" "IPv6 prefix /\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, 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") #endif /* HAVE_IPV6 */ /* 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") #ifdef HAVE_IPV6 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") #endif /* HAVE_IPV6 */ /* Aggreagete address: advertise-map Set condition to advertise attribute as-set Generate AS set path information attribute-map Set attributes of aggregate route-map Set parameters of aggregate summary-only Filter more specific routes from updates suppress-map Conditionally filter more specific routes from updates */ struct bgp_aggregate { /* Summary-only flag. */ u_char summary_only; /* AS set generation. */ u_char as_set; /* Route-map for aggregated route. */ struct route_map *map; /* Suppress-count. */ unsigned long count; /* SAFI configuration. */ safi_t safi; }; 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); } 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 in_addr nexthop; u_int32_t med = 0; struct bgp_info *ri; struct bgp_info *new; int first = 1; unsigned long match = 0; /* Record adding route's nexthop and med. */ if (rinew) { nexthop = rinew->attr->nexthop; med = rinew->attr->med; } /* ORIGIN attribute: If at least one route among routes that are aggregated has ORIGIN with the value INCOMPLETE, then the aggregated route must have the ORIGIN attribute with the value INCOMPLETE. Otherwise, if at least one route among routes that are aggregated has ORIGIN with the value EGP, then the aggregated route must have the origin attribute with the value EGP. In all other case the value of the ORIGIN attribute of the aggregated route is INTERNAL. */ origin = BGP_ORIGIN_IGP; table = bgp->rib[afi][safi]; top = bgp_node_get (table, p); for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) if (rn->p.prefixlen > p->prefixlen) { match = 0; for (ri = rn->info; ri; ri = ri->next) { if (BGP_INFO_HOLDDOWN (ri)) continue; if (del && ri == del) continue; if (! rinew && first) { nexthop = ri->attr->nexthop; med = ri->attr->med; first = 0; } #ifdef AGGREGATE_NEXTHOP_CHECK if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop) || ri->attr->med != med) { if (aspath) aspath_free (aspath); if (community) community_free (community); bgp_unlock_node (rn); bgp_unlock_node (top); return; } #endif /* AGGREGATE_NEXTHOP_CHECK */ if (ri->sub_type != BGP_ROUTE_AGGREGATE) { if (aggregate->summary_only) { (bgp_info_extra_get (ri))->suppress++; bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } aggregate->count++; if (aggregate->as_set) { if (origin < ri->attr->origin) origin = ri->attr->origin; if (aspath) { asmerge = aspath_aggregate (aspath, ri->attr->aspath); aspath_free (aspath); aspath = asmerge; } else aspath = aspath_dup (ri->attr->aspath); if (ri->attr->community) { if (community) { commerge = community_merge (community, ri->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (ri->attr->community); } } } } if (match) bgp_process (bgp, rn, afi, safi); } bgp_unlock_node (top); if (rinew) { aggregate->count++; if (aggregate->summary_only) (bgp_info_extra_get (rinew))->suppress++; if (aggregate->as_set) { if (origin < rinew->attr->origin) origin = rinew->attr->origin; if (aspath) { asmerge = aspath_aggregate (aspath, rinew->attr->aspath); aspath_free (aspath); aspath = asmerge; } else aspath = aspath_dup (rinew->attr->aspath); if (rinew->attr->community) { if (community) { commerge = community_merge (community, rinew->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (rinew->attr->community); } } } if (aggregate->count > 0) { rn = bgp_node_get (table, p); new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_AGGREGATE; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); new->uptime = bgp_clock (); 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) 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) 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); } 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; table = bgp->rib[afi][safi]; /* Sanity check. */ if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) return; if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) return; /* If routes exists below this node, generate aggregate routes. */ top = bgp_node_get (table, p); for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) if (rn->p.prefixlen > p->prefixlen) { match = 0; for (ri = rn->info; ri; ri = ri->next) { if (BGP_INFO_HOLDDOWN (ri)) continue; if (ri->sub_type != BGP_ROUTE_AGGREGATE) { /* summary-only aggregate route suppress aggregated route announcement. */ if (aggregate->summary_only) { (bgp_info_extra_get (ri))->suppress++; bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } /* as-set aggregate route generate origin, as path, community aggregation. */ if (aggregate->as_set) { if (origin < ri->attr->origin) origin = ri->attr->origin; if (aspath) { asmerge = aspath_aggregate (aspath, ri->attr->aspath); aspath_free (aspath); aspath = asmerge; } else aspath = aspath_dup (ri->attr->aspath); if (ri->attr->community) { if (community) { commerge = community_merge (community, ri->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (ri->attr->community); } } aggregate->count++; } } /* If this node is suppressed, process the change. */ if (match) bgp_process (bgp, rn, afi, safi); } bgp_unlock_node (top); /* Add aggregate route to BGP table. */ if (aggregate->count) { rn = bgp_node_get (table, p); new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_AGGREGATE; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); new->uptime = bgp_clock (); bgp_info_add (rn, new); bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); } } void bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; struct bgp_node *top; struct bgp_node *rn; struct bgp_info *ri; unsigned long match; table = bgp->rib[afi][safi]; if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) return; if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) return; /* If routes exists below this node, generate aggregate routes. */ top = bgp_node_get (table, p); for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) if (rn->p.prefixlen > p->prefixlen) { match = 0; for (ri = rn->info; ri; ri = ri->next) { if (BGP_INFO_HOLDDOWN (ri)) continue; if (ri->sub_type != BGP_ROUTE_AGGREGATE) { if (aggregate->summary_only && ri->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") #ifdef HAVE_IPV6 DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, "aggregate-address X:X::X:X/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0, 0); } DEFUN (ipv6_aggregate_address_summary_only, ipv6_aggregate_address_summary_only_cmd, "aggregate-address X:X::X:X/M summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, AGGREGATE_SUMMARY_ONLY, 0); } DEFUN (no_ipv6_aggregate_address, no_ipv6_aggregate_address_cmd, "no aggregate-address X:X::X:X/M", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") { return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); } DEFUN (no_ipv6_aggregate_address_summary_only, no_ipv6_aggregate_address_summary_only_cmd, "no aggregate-address X:X::X:X/M summary-only", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") { return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (ipv6_aggregate_address, old_ipv6_aggregate_address_cmd, "ipv6 bgp aggregate-address X:X::X:X/M", IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") ALIAS (ipv6_aggregate_address_summary_only, old_ipv6_aggregate_address_summary_only_cmd, "ipv6 bgp aggregate-address X:X::X:X/M summary-only", IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") ALIAS (no_ipv6_aggregate_address, old_no_ipv6_aggregate_address_cmd, "no ipv6 bgp aggregate-address X:X::X:X/M", NO_STR IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") ALIAS (no_ipv6_aggregate_address_summary_only, old_no_ipv6_aggregate_address_summary_only_cmd, "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", NO_STR IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") #endif /* HAVE_IPV6 */ /* Redistribute route treatment. */ void bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, const struct in6_addr *nexthop6, u_int32_t metric, u_char type) { 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; #ifdef HAVE_IPV6 if (nexthop6) { struct attr_extra *extra = bgp_attr_extra_get(&attr); extra->mp_nexthop_global = *nexthop6; extra->mp_nexthop_len = 16; } #endif attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); 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].map) { 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 = bgp_info_new (); new->type = type; new->sub_type = BGP_ROUTE_REDISTRIBUTE; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = new_attr; new->uptime = bgp_clock (); 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_HISTORY)) vty_out (vty, "*"); else vty_out (vty, " "); /* Selected */ if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, "h"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) vty_out (vty, "d"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) vty_out (vty, ">"); else vty_out (vty, " "); /* Internal route. */ if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as)) vty_out (vty, "i"); else vty_out (vty, " "); } /* 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) { if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { int len; char buf[BUFSIZ]; len = vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->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, " "); } #endif /* HAVE_IPV6 */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, "%10u", attr->med); else vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) vty_out (vty, "%7u", attr->local_pref); else vty_out (vty, " "); vty_out (vty, "%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) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { int len; char buf[BUFSIZ]; 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, " "); } #endif /* HAVE_IPV6 */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, "%10u", attr->med); else vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) vty_out (vty, "%7u", attr->local_pref); else vty_out (vty, " "); vty_out (vty, "%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) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 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)); } #endif /* HAVE_IPV6 */ } 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 ? inet_ntoa (attr->extra->mp_nexthop_global_in) : inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else { assert (attr->extra); vty_out (vty, " %s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, INET6_ADDRSTRLEN)); } #endif /* HAVE_IPV6 */ if (binfo->peer == bgp->peer_self) { vty_out (vty, " from %s ", p->family == AF_INET ? "0.0.0.0" : "::"); vty_out (vty, "(%s)", inet_ntoa(bgp->router_id)); } else { if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) vty_out (vty, " (inaccessible)"); else if (binfo->extra && binfo->extra->igpmetric) vty_out (vty, " (metric %u)", binfo->extra->igpmetric); vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); else vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ)); } vty_out (vty, "%s", VTY_NEWLINE); #ifdef HAVE_IPV6 /* display nexthop local */ if (attr->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); } #endif /* HAVE_IPV6 */ /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */ vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, ", metric %u", attr->med); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) vty_out (vty, ", localpref %u", attr->local_pref); else vty_out (vty, ", localpref %u", bgp->default_local_pref); if (attr->extra && attr->extra->weight != 0) vty_out (vty, ", weight %u", attr->extra->weight); if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, ", valid"); if (binfo->peer != bgp->peer_self) { if (binfo->peer->as == binfo->peer->local_as) vty_out (vty, ", internal"); else vty_out (vty, ", %s", (bgp_confederation_peers_check(bgp, binfo->peer->as) ? "confed-external" : "external")); } else if (binfo->sub_type == BGP_ROUTE_AGGREGATE) vty_out (vty, ", aggregated, local"); else if (binfo->type != ZEBRA_ROUTE_BGP) vty_out (vty, ", sourced"); else vty_out (vty, ", sourced, local"); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) vty_out (vty, ", atomic-aggregate"); if (CHECK_FLAG (binfo->flags, BGP_INFO_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 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 7 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, i - internal,%s 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_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; /* This is first entry point, so reset total line. */ output_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) { 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_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 network exists%s", VTY_NEWLINE); } else vty_out (vty, "%sTotal number of prefixes %ld%s", VTY_NEWLINE, output_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; p = &rn->p; vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", (safi == SAFI_MPLS_VPN ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), safi == SAFI_MPLS_VPN ? ":" : "", inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), p->prefixlen, VTY_NEWLINE); for (ri = rn->info; ri; ri = ri->next) { count++; if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) { best = count; if (ri->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) { 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; /* Check IP address argument. */ ret = str2prefix (ip_str, &match); if (! ret) { vty_out (vty, "address is malformed%s", VTY_NEWLINE); return CMD_WARNING; } match.family = afi2family (afi); if (safi == SAFI_MPLS_VPN) { for (rn = bgp_table_top (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_MPLS_VPN); header = 0; } display++; route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN); } 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++; 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) { 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); } /* 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); } ALIAS (show_ip_bgp_ipv4, 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") DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, "show ip bgp A.B.C.D", SHOW_STR IP_STR BGP_STR "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); } DEFUN (show_ip_bgp_ipv4_route, show_ip_bgp_ipv4_route_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } ALIAS (show_ip_bgp_ipv4_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") DEFUN (show_ip_bgp_vpnv4_all_route, show_ip_bgp_vpnv4_all_route_cmd, "show ip bgp vpnv4 all A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); } DEFUN (show_ip_bgp_vpnv4_rd_route, show_ip_bgp_vpnv4_rd_route_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Network in the BGP routing table to display\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); } DEFUN (show_ip_bgp_prefix, show_ip_bgp_prefix_cmd, "show ip bgp A.B.C.D/M", SHOW_STR IP_STR BGP_STR "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (show_ip_bgp_ipv4_prefix, show_ip_bgp_ipv4_prefix_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } ALIAS (show_ip_bgp_ipv4_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") DEFUN (show_ip_bgp_vpnv4_all_prefix, show_ip_bgp_vpnv4_all_prefix_cmd, "show ip bgp vpnv4 all A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); } DEFUN (show_ip_bgp_vpnv4_rd_prefix, show_ip_bgp_vpnv4_rd_prefix_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); } DEFUN (show_ip_bgp_view, show_ip_bgp_view_cmd, "show ip bgp view WORD", SHOW_STR IP_STR BGP_STR "BGP view\n" "BGP view name\n") { 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" "BGP view name\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } DEFUN (show_ip_bgp_view_prefix, show_ip_bgp_view_prefix_cmd, "show ip bgp view WORD A.B.C.D/M", SHOW_STR IP_STR BGP_STR "BGP view\n" "BGP view name\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } #ifdef HAVE_IPV6 DEFUN (show_bgp, show_bgp_cmd, "show bgp", SHOW_STR BGP_STR) { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } ALIAS (show_bgp, show_bgp_ipv6_cmd, "show bgp ipv6", SHOW_STR BGP_STR "Address family\n") 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); } /* 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); } ALIAS (show_bgp_route, show_bgp_ipv6_route_cmd, "show bgp ipv6 X:X::X:X", SHOW_STR BGP_STR "Address family\n" "Network in the BGP routing table to display\n") 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); return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } /* old command */ DEFUN (show_ipv6_bgp_route, show_ipv6_bgp_route_cmd, "show ipv6 bgp X:X::X:X", SHOW_STR IP_STR BGP_STR "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); } DEFUN (show_bgp_prefix, show_bgp_prefix_cmd, "show bgp X:X::X:X/M", SHOW_STR BGP_STR "IPv6 prefix /\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); } ALIAS (show_bgp_prefix, show_bgp_ipv6_prefix_cmd, "show bgp ipv6 X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "IPv6 prefix /\n") 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); return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } /* 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); } 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); } ALIAS (show_bgp_view, show_bgp_view_ipv6_cmd, "show bgp view WORD ipv6", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n") 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); } ALIAS (show_bgp_view_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") 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); } ALIAS (show_bgp_view_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") /* 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); } /* old command */ DEFUN (show_ipv6_mbgp_prefix, show_ipv6_mbgp_prefix_cmd, "show ipv6 mbgp X:X::X:X/M", SHOW_STR IP_STR MBGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); } #endif 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); } DEFUN (show_ip_bgp_ipv4_regexp, show_ip_bgp_ipv4_regexp_cmd, "show ip bgp ipv4 (unicast|multicast) regexp .LINE", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, bgp_show_type_regexp); return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, bgp_show_type_regexp); } #ifdef HAVE_IPV6 DEFUN (show_bgp_regexp, show_bgp_regexp_cmd, "show bgp regexp .LINE", SHOW_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, bgp_show_type_regexp); } ALIAS (show_bgp_regexp, show_bgp_ipv6_regexp_cmd, "show bgp ipv6 regexp .LINE", SHOW_STR BGP_STR "Address family\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") /* old command */ DEFUN (show_ipv6_bgp_regexp, show_ipv6_bgp_regexp_cmd, "show ipv6 bgp regexp .LINE", SHOW_STR IP_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, bgp_show_type_regexp); } /* old command */ DEFUN (show_ipv6_mbgp_regexp, show_ipv6_mbgp_regexp_cmd, "show ipv6 mbgp regexp .LINE", SHOW_STR IP_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the MBGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, bgp_show_type_regexp); } #endif /* HAVE_IPV6 */ 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); } DEFUN (show_ip_bgp_ipv4_prefix_list, show_ip_bgp_ipv4_prefix_list_cmd, "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_prefix_list); return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_prefix_list); } #ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_list, show_bgp_prefix_list_cmd, "show bgp prefix-list WORD", SHOW_STR BGP_STR "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_list); } ALIAS (show_bgp_prefix_list, show_bgp_ipv6_prefix_list_cmd, "show bgp ipv6 prefix-list WORD", SHOW_STR BGP_STR "Address family\n" "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") /* old command */ DEFUN (show_ipv6_bgp_prefix_list, show_ipv6_bgp_prefix_list_cmd, "show ipv6 bgp prefix-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes matching the prefix-list\n" "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_list); } /* old command */ DEFUN (show_ipv6_mbgp_prefix_list, show_ipv6_mbgp_prefix_list_cmd, "show ipv6 mbgp prefix-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the prefix-list\n" "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_prefix_list); } #endif /* HAVE_IPV6 */ 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); } DEFUN (show_ip_bgp_ipv4_filter_list, show_ip_bgp_ipv4_filter_list_cmd, "show ip bgp ipv4 (unicast|multicast) filter-list WORD", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_filter_list); return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_filter_list); } #ifdef HAVE_IPV6 DEFUN (show_bgp_filter_list, show_bgp_filter_list_cmd, "show bgp filter-list WORD", SHOW_STR BGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_filter_list); } ALIAS (show_bgp_filter_list, show_bgp_ipv6_filter_list_cmd, "show bgp ipv6 filter-list WORD", SHOW_STR BGP_STR "Address family\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") /* old command */ DEFUN (show_ipv6_bgp_filter_list, show_ipv6_bgp_filter_list_cmd, "show ipv6 bgp filter-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_filter_list); } /* old command */ DEFUN (show_ipv6_mbgp_filter_list, show_ipv6_mbgp_filter_list_cmd, "show ipv6 mbgp filter-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_filter_list); } #endif /* HAVE_IPV6 */ 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); } DEFUN (show_ip_bgp_ipv4_route_map, show_ip_bgp_ipv4_route_map_cmd, "show ip bgp ipv4 (unicast|multicast) route-map WORD", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_route_map); return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_route_map); } DEFUN (show_bgp_route_map, show_bgp_route_map_cmd, "show bgp route-map WORD", SHOW_STR BGP_STR "Display routes matching the route-map\n" "A route-map to match on\n") { return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_route_map); } ALIAS (show_bgp_route_map, show_bgp_ipv6_route_map_cmd, "show bgp ipv6 route-map WORD", SHOW_STR BGP_STR "Address family\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFUN (show_ip_bgp_cidr_only, show_ip_bgp_cidr_only_cmd, "show ip bgp cidr-only", SHOW_STR IP_STR BGP_STR "Display only routes with non-natural netmasks\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, 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); } 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); } #ifdef HAVE_IPV6 DEFUN (show_bgp_community_all, show_bgp_community_all_cmd, "show bgp community", SHOW_STR BGP_STR "Display routes matching the communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_community_all, 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); } #endif /* HAVE_IPV6 */ 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; 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; } return bgp_show (vty, bgp, afi, safi, (exact ? bgp_show_type_community_exact : bgp_show_type_community), com); } 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_bgp_view_afi_safi_community_all, show_bgp_view_afi_safi_community_all_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", #else "show bgp view WORD ipv4 (unicast|multicast) community", #endif SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address Family modifier\n" "Address Family modifier\n" "Display routes containing 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; } #ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; #else afi = AFI_IP; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; #endif 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, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", #else "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", #endif SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "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; #ifdef HAVE_IPV6 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); #else afi = AFI_IP; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); #endif } ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community2_cmd, #ifdef HAVE_IPV6 "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)", #else "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #endif SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "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, #ifdef HAVE_IPV6 "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)", #else "show bgp view WORD 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)", #endif SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "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, #ifdef HAVE_IPV6 "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)", #else "show bgp view WORD 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)", #endif SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "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") #ifdef HAVE_IPV6 DEFUN (show_bgp_community, show_bgp_community_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { return bgp_show_community (vty, 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") #endif /* HAVE_IPV6 */ 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); } #ifdef HAVE_IPV6 DEFUN (show_bgp_community_list, show_bgp_community_list_cmd, "show bgp community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community_list, show_bgp_ipv6_community_list_cmd, "show bgp ipv6 community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") /* old command */ DEFUN (show_ipv6_bgp_community_list, show_ipv6_bgp_community_list_cmd, "show ipv6 bgp community-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes matching the community-list\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_community_list, show_ipv6_mbgp_community_list_cmd, "show ipv6 mbgp community-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the community-list\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST); } DEFUN (show_bgp_community_list_exact, show_bgp_community_list_exact_cmd, "show bgp community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community_list_exact, show_bgp_ipv6_community_list_exact_cmd, "show bgp ipv6 community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR "Address family\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") /* old command */ DEFUN (show_ipv6_bgp_community_list_exact, show_ipv6_bgp_community_list_exact_cmd, "show ipv6 bgp community-list WORD exact-match", SHOW_STR IPV6_STR BGP_STR "Display routes matching the community-list\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_community_list_exact, show_ipv6_mbgp_community_list_exact_cmd, "show ipv6 mbgp community-list WORD exact-match", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the community-list\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ 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); } DEFUN (show_ip_bgp_ipv4_prefix_longer, show_ip_bgp_ipv4_prefix_longer_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_prefix_longer); return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_prefix_longer); } DEFUN (show_ip_bgp_flap_address, show_ip_bgp_flap_address_cmd, "show ip bgp flap-statistics A.B.C.D", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_address); } DEFUN (show_ip_bgp_flap_prefix, show_ip_bgp_flap_prefix_cmd, "show ip bgp flap-statistics A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_prefix); } #ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_longer, show_bgp_prefix_longer_cmd, "show bgp X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "IPv6 prefix /\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } ALIAS (show_bgp_prefix_longer, show_bgp_ipv6_prefix_longer_cmd, "show bgp ipv6 X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "IPv6 prefix /\n" "Display route and more specific routes\n") /* old command */ DEFUN (show_ipv6_bgp_prefix_longer, show_ipv6_bgp_prefix_longer_cmd, "show ipv6 bgp X:X::X:X/M longer-prefixes", SHOW_STR IPV6_STR BGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } /* old command */ DEFUN (show_ipv6_mbgp_prefix_longer, show_ipv6_mbgp_prefix_longer_cmd, "show ipv6 mbgp X:X::X:X/M longer-prefixes", SHOW_STR IPV6_STR MBGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_prefix_longer); } #endif /* HAVE_IPV6 */ 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 exist for the AFI/SAFI%s", 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 exist%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; } if (strncmp (safi_str, "m", 1) == 0) safi = SAFI_MULTICAST; else if (strncmp (safi_str, "u", 1) == 0) safi = SAFI_UNICAST; else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0) safi = SAFI_MPLS_LABELED_VPN; else { 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) (unicast|multicast) statistics", SHOW_STR BGP_STR "Address family\n" "Address family\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) (unicast|multicast) statistics", SHOW_STR BGP_STR "BGP view\n" "Address family\n" "Address family\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); } 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); } #ifdef HAVE_IPV6 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); } ALIAS (show_bgp_view_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") 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_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") 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); } #endif /* HAVE_IPV6 */ 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") 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_view_afi_safi_neighbor_adv_recd_routes, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", #else "show bgp view WORD ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", #endif SHOW_STR BGP_STR "BGP view\n" "BGP view name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "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; #ifdef HAVE_IPV6 peer = peer_lookup_in_view (vty, argv[0], argv[3]); #else peer = peer_lookup_in_view (vty, argv[0], argv[2]); #endif if (! peer) return CMD_WARNING; #ifdef HAVE_IPV6 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; #else afi = AFI_IP; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; in = (strncmp (argv[3], "r", 1) == 0) ? 1 : 0; #endif 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; } #ifdef HAVE_IPV6 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") 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; } ALIAS (show_bgp_neighbor_received_prefix_filter, show_bgp_ipv6_neighbor_received_prefix_filter_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") /* old command */ 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; } ALIAS (show_bgp_view_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") #endif /* HAVE_IPV6 */ 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" "BGP 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" "BGP 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" "BGP 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); } 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_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" "BGP 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); } 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_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" "BGP 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); } 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") 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" "BGP 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); } 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") #ifdef HAVE_IPV6 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" "BGP 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_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" "BGP 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") 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" "BGP 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); } ALIAS (show_bgp_view_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" "BGP 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") 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" "BGP 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_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" "BGP 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 flap statistics of the routes learned from neighbor\n") 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_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_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_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") 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" "BGP 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_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" "BGP 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" "BGP 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); } ALIAS (show_bgp_view_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") 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" "BGP 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); } 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" "BGP 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); } ALIAS (show_bgp_view_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") 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" "BGP 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); } 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") #endif /* HAVE_IPV6 */ struct bgp_table *bgp_distance_table; struct bgp_distance { /* Distance value for the IP source prefix. */ u_char distance; /* Name of the access-list to be matched. */ char *access_list; }; 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); } 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_ipv4 p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); /* Get BGP distance node. */ rn = bgp_node_get (bgp_distance_table, (struct prefix *) &p); if (rn->info) { bdistance = rn->info; bgp_unlock_node (rn); } else { bdistance = bgp_distance_new (); rn->info = bdistance; } /* Set distance value. */ bdistance->distance = distance; /* Reset access-list configuration. */ if (bdistance->access_list) { free (bdistance->access_list); bdistance->access_list = NULL; } if (access_list_str) bdistance->access_list = strdup (access_list_str); return CMD_SUCCESS; } 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_ipv4 p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); rn = bgp_node_lookup (bgp_distance_table, (struct prefix *)&p); if (! rn) { vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); return CMD_WARNING; } bdistance = rn->info; if (bdistance->access_list) free (bdistance->access_list); bgp_distance_free (bdistance); rn->info = NULL; bgp_unlock_node (rn); bgp_unlock_node (rn); return CMD_SUCCESS; } /* 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; } } DEFUN (bgp_distance, bgp_distance_cmd, "distance bgp <1-255> <1-255> <1-255>", "Define an administrative distance\n" "BGP distance\n" "Distance for routes external to the AS\n" "Distance for routes internal to the AS\n" "Distance for local routes\n") { struct bgp *bgp; bgp = vty->index; bgp->distance_ebgp = atoi (argv[0]); bgp->distance_ibgp = atoi (argv[1]); bgp->distance_local = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (no_bgp_distance, no_bgp_distance_cmd, "no distance bgp <1-255> <1-255> <1-255>", NO_STR "Define an administrative distance\n" "BGP distance\n" "Distance for routes external to the AS\n" "Distance for routes internal to the AS\n" "Distance for local routes\n") { struct bgp *bgp; bgp = vty->index; bgp->distance_ebgp= 0; bgp->distance_ibgp = 0; bgp->distance_local = 0; return CMD_SUCCESS; } ALIAS (no_bgp_distance, no_bgp_distance2_cmd, "no distance bgp", NO_STR "Define an administrative distance\n" "BGP distance\n") DEFUN (bgp_distance_source, bgp_distance_source_cmd, "distance <1-255> A.B.C.D/M", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") { bgp_distance_set (vty, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (no_bgp_distance_source, no_bgp_distance_source_cmd, "no distance <1-255> A.B.C.D/M", NO_STR "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") { bgp_distance_unset (vty, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (bgp_distance_source_access_list, bgp_distance_source_access_list_cmd, "distance <1-255> A.B.C.D/M WORD", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") { bgp_distance_set (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (no_bgp_distance_source_access_list, no_bgp_distance_source_access_list_cmd, "no distance <1-255> A.B.C.D/M WORD", NO_STR "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") { bgp_distance_unset (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (bgp_damp_set, bgp_damp_set_cmd, "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" "Value to start reusing a route\n" "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") { struct bgp *bgp; int half = DEFAULT_HALF_LIFE * 60; int reuse = DEFAULT_REUSE; int suppress = DEFAULT_SUPPRESS; int max = 4 * half; if (argc == 4) { half = atoi (argv[0]) * 60; reuse = atoi (argv[1]); suppress = atoi (argv[2]); max = atoi (argv[3]) * 60; } else if (argc == 1) { half = atoi (argv[0]) * 60; max = 4 * half; } bgp = vty->index; return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty), half, reuse, suppress, max); } ALIAS (bgp_damp_set, bgp_damp_set2_cmd, "bgp dampening <1-45>", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n") ALIAS (bgp_damp_set, bgp_damp_set3_cmd, "bgp dampening", "BGP Specific commands\n" "Enable route-flap dampening\n") DEFUN (bgp_damp_unset, bgp_damp_unset_cmd, "no bgp dampening", NO_STR "BGP Specific commands\n" "Enable route-flap dampening\n") { struct bgp *bgp; bgp = vty->index; return bgp_damp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty)); } ALIAS (bgp_damp_unset, bgp_damp_unset2_cmd, "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", NO_STR "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" "Value to start reusing a route\n" "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") DEFUN (show_ip_bgp_dampened_paths, show_ip_bgp_dampened_paths_cmd, "show ip bgp dampened-paths", SHOW_STR IP_STR BGP_STR "Display paths suppressed due to dampening\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths, NULL); } 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); } /* 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) { for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; if ((table = rn->info) != NULL) if ((rm = bgp_node_match (table, &match)) != NULL) { if (! prefix_check || rm->p.prefixlen == match.prefixlen) { ri = rm->info; while (ri) { if (ri->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); } 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) return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write); /* Network configuration. */ for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { p = &rn->p; /* "address-family" display. */ bgp_config_write_family_header (vty, afi, safi, write); /* "network" configuration display. */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) { u_int32_t destination; struct in_addr netmask; destination = ntohl (p->u.prefix4.s_addr); masklen2ip (p->prefixlen, &netmask); vty_out (vty, " network %s", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN)); if ((IN_CLASSC (destination) && p->prefixlen == 24) || (IN_CLASSB (destination) && p->prefixlen == 16) || (IN_CLASSA (destination) && p->prefixlen == 8) || p->u.prefix4.s_addr == 0) { /* Natural mask is not display. */ } else vty_out (vty, " mask %s", inet_ntoa (netmask)); } else { vty_out (vty, " network %s/%d", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); } if (bgp_static->rmap.name) vty_out (vty, " route-map %s", bgp_static->rmap.name); else { if (bgp_static->backdoor) vty_out (vty, " backdoor"); } vty_out (vty, "%s", VTY_NEWLINE); } /* Aggregate-address configuration. */ for (rn = bgp_table_top (bgp->aggregate[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_aggregate = rn->info) != NULL) { p = &rn->p; /* "address-family" display. */ bgp_config_write_family_header (vty, afi, safi, write); if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) { struct in_addr netmask; masklen2ip (p->prefixlen, &netmask); vty_out (vty, " aggregate-address %s %s", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), inet_ntoa (netmask)); } else { vty_out (vty, " aggregate-address %s/%d", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); } if (bgp_aggregate->as_set) vty_out (vty, " as-set"); if (bgp_aggregate->summary_only) vty_out (vty, " summary-only"); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } int bgp_config_write_distance (struct vty *vty, struct bgp *bgp) { struct bgp_node *rn; struct bgp_distance *bdistance; /* Distance configuration. */ if (bgp->distance_ebgp && bgp->distance_ibgp && bgp->distance_local && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) vty_out (vty, " distance bgp %d %d %d%s", bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, VTY_NEWLINE); for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) if ((bdistance = rn->info) != NULL) { vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, bdistance->access_list ? bdistance->access_list : "", VTY_NEWLINE); } return 0; } /* Allocate routing table structure and install commands. */ void bgp_route_init (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_ip_bgp_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_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_bgp_ipv4_safi_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_cmd); install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); install_element (VIEW_NODE, &show_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_ip_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_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_bgp_view_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_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_ip_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_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_bgp_ipv4_safi_prefix_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_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_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_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd); install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_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); /* prefix count */ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_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_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd); install_element (VIEW_NODE, &show_bgp_route_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_prefix_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_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); install_element (VIEW_NODE, &show_bgp_community_all_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); install_element (VIEW_NODE, &show_bgp_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); install_element (VIEW_NODE, &show_bgp_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); install_element (VIEW_NODE, &show_bgp_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); install_element (VIEW_NODE, &show_bgp_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); install_element (VIEW_NODE, &show_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_view_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd); install_element (VIEW_NODE, &show_bgp_view_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_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_route_cmd); 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_prefix_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_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd); install_element (ENABLE_NODE, &show_bgp_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (ENABLE_NODE, &show_bgp_route_map_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); install_element (ENABLE_NODE, &show_bgp_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_community_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); install_element (ENABLE_NODE, &show_bgp_community2_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); install_element (ENABLE_NODE, &show_bgp_community3_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); install_element (ENABLE_NODE, &show_bgp_community4_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_view_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_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_vpnv4_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); /* old command */ install_element (VIEW_NODE, &show_ipv6_bgp_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); /* old command */ install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); /* old command */ install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); /* old command */ install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); /* old command */ install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); #endif /* HAVE_IPV6 */ install_element (BGP_NODE, &bgp_distance_cmd); install_element (BGP_NODE, &no_bgp_distance_cmd); install_element (BGP_NODE, &no_bgp_distance2_cmd); install_element (BGP_NODE, &bgp_distance_source_cmd); install_element (BGP_NODE, &no_bgp_distance_source_cmd); install_element (BGP_NODE, &bgp_distance_source_access_list_cmd); install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd); install_element (BGP_NODE, &bgp_damp_set_cmd); install_element (BGP_NODE, &bgp_damp_set2_cmd); install_element (BGP_NODE, &bgp_damp_set3_cmd); install_element (BGP_NODE, &bgp_damp_unset_cmd); install_element (BGP_NODE, &bgp_damp_unset2_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); /* 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); #ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd); #endif } void bgp_route_finish (void) { bgp_table_unlock (bgp_distance_table); bgp_distance_table = NULL; } quagga-0.99.22.4/bgpd/bgp_route.h0000644000175000017500000002055212177450262013312 00000000000000/* 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 "bgp_table.h" /* 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; /* 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; /* MPLS label. */ u_char tag[3]; }; /* 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 }; /* 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_sanity_check (struct peer *, int, u_char *, bgp_size_t); extern int bgp_nlri_parse (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); 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_vpnv4 (struct vty *vty, const char *, const char *, const char *); extern int bgp_static_unset_vpnv4 (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 *); 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 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); #endif /* _QUAGGA_BGP_ROUTE_H */ quagga-0.99.22.4/bgpd/bgp_routemap.c0000644000175000017500000030716012177450262014006 00000000000000/* 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_vty.h" /* Memo of route-map commands. o Cisco route-map match as-path : Done community : Done interface : Not yet ip address : Done ip next-hop : Done ip route-source : 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 : (This will not be implemented by bgpd) set as-path prepend : Done as-path tag : Not yet automatic-tag : (This will not be implemented by bgpd) community : Done comm-list : Not yet dampning : Not yet default : (This will not be implemented by bgpd) interface : (This will not be implemented by bgpd) ip default : (This will not be implemented by bgpd) ip next-hop : Done ip precedence : (This will not be implemented by bgpd) ip tos : (This will not be implemented by bgpd) level : (This will not be implemented by bgpd) local-preference : Done metric : Done metric-type : Not yet origin : Done tag : (This will not be implemented by bgpd) weight : Done o Local extention set ipv6 next-hop global: Done set ipv6 next-hop local : Done set as-path exclude : Done */ /* '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 = { .sa.sa_family = AF_INET, .sin.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 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 *med; struct bgp_info *bgp_info; if (type == RMAP_BGP) { med = rule; bgp_info = object; if (bgp_info->attr->med == *med) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match metric' match statement. `arg' is MED value */ static void * route_match_metric_compile (const char *arg) { u_int32_t *med; char *endptr = NULL; unsigned long tmpval; /* Metric 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; med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (!med) return med; *med = tmpval; return med; } /* 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 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 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; #if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 r = random(); #else r = (long) rand(); #endif switch (*(unsigned *) rule) { case 0: break; case RAND_MAX: return RMAP_MATCH; default: if (r < *(unsigned *) rule) { return RMAP_MATCH; } } return RMAP_NOMATCH; } static void * route_match_probability_compile (const char *arg) { unsigned *lobule; unsigned perc; #if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 srandom (time (NULL)); #else srand (time (NULL)); #endif perc = atoi (arg); lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); 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' */ /* 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) { u_int32_t *local_pref; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ local_pref = rule; bgp_info = object; /* Set local preference value. */ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); bgp_info->attr->local_pref = *local_pref; } return RMAP_OKAY; } /* set local preference compilation. */ static void * route_set_local_pref_compile (const char *arg) { unsigned long tmp; u_int32_t *local_pref; char *endptr = NULL; /* Local preference value shoud be integer. */ if (! all_digit (arg)) return NULL; errno = 0; tmp = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || tmp > UINT32_MAX) return NULL; local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (!local_pref) return local_pref; *local_pref = tmp; return local_pref; } /* Free route map's local preference value. */ static void route_set_local_pref_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_local_pref_cmd = { "local-preference", route_set_local_pref, route_set_local_pref_compile, route_set_local_pref_free, }; /* `set weight WEIGHT' */ /* Set weight. */ static route_map_result_t route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *weight; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ weight = rule; bgp_info = object; /* Set weight value. */ 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 compilation. */ static void * route_set_weight_compile (const char *arg) { unsigned long tmp; u_int32_t *weight; char *endptr = NULL; /* Local preference value shoud be integer. */ if (! all_digit (arg)) return NULL; errno = 0; tmp = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || tmp > UINT32_MAX) return NULL; weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (weight == NULL) return weight; *weight = tmp; return weight; } /* Free route map's local preference value. */ static void route_set_weight_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_weight_cmd = { "weight", route_set_weight, route_set_weight_compile, route_set_weight_free, }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { char *metric; u_int32_t metric_val; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ metric = rule; bgp_info = object; if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) bgp_info->attr->med = 0; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (all_digit (metric)) { metric_val = strtoul (metric, (char **)NULL, 10); bgp_info->attr->med = metric_val; } else { metric_val = strtoul (metric+1, (char **)NULL, 10); if (strncmp (metric, "+", 1) == 0) { if (bgp_info->attr->med/2 + metric_val/2 > BGP_MED_MAX/2) bgp_info->attr->med = BGP_MED_MAX - 1; else bgp_info->attr->med += metric_val; } else if (strncmp (metric, "-", 1) == 0) { if (bgp_info->attr->med <= metric_val) bgp_info->attr->med = 0; else bgp_info->attr->med -= metric_val; } } } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { u_int32_t metric; unsigned long larg; char *endptr = NULL; if (all_digit (arg)) { /* set metric value check*/ errno = 0; larg = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; metric = larg; } else { /* set metric +/-value check */ if ((strncmp (arg, "+", 1) != 0 && strncmp (arg, "-", 1) != 0) || (! all_digit (arg+1))) return NULL; errno = 0; larg = strtoul (arg+1, &endptr, 10); if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; metric = larg; } return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* 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 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) { aspath = rule; binfo = object; if (binfo->attr->aspath->refcnt) new = aspath_dup (binfo->attr->aspath); else new = binfo->attr->aspath; aspath_prepend (aspath, new); binfo->attr->aspath = new; } return RMAP_OKAY; } /* Compile function for as-path prepend. */ static void * route_set_aspath_prepend_compile (const char *arg) { struct aspath *aspath; aspath = aspath_str2aspath (arg); if (! aspath) return NULL; return aspath; } /* Compile function for as-path prepend. */ static void route_set_aspath_prepend_free (void *rule) { struct aspath *aspath = rule; aspath_free (aspath); } /* Set metric rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", route_set_aspath_prepend, route_set_aspath_prepend_compile, route_set_aspath_prepend_free, }; /* `set 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; } /* FIXME: consider using route_set_aspath_prepend_compile() and * route_set_aspath_prepend_free(), which two below function are * exact clones of. */ /* Compile function for as-path exclude. */ static void * route_set_aspath_exclude_compile (const char *arg) { struct aspath *aspath; aspath = aspath_str2aspath (arg); if (! aspath) return NULL; return aspath; } static void route_set_aspath_exclude_free (void *rule) { struct aspath *aspath = rule; aspath_free (aspath); } /* Set ASn exlude rule structure. */ struct route_map_rule_cmd route_set_aspath_exclude_cmd = { "as-path exclude", route_set_aspath_exclude, route_set_aspath_exclude_compile, route_set_aspath_exclude_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 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. */ static route_map_result_t route_set_ecommunity_rt (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct ecommunity *ecom; struct ecommunity *new_ecom; struct ecommunity *old_ecom; struct bgp_info *bgp_info; if (type == RMAP_BGP) { ecom = rule; bgp_info = object; if (! ecom) return RMAP_OKAY; /* We assume additive for Extended Community. */ old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; if (old_ecom) new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); else new_ecom = ecommunity_dup (ecom); bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); if (old_ecom) ecommunity_unintern (&old_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. */ static void route_set_ecommunity_rt_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_rt, route_set_ecommunity_rt_compile, route_set_ecommunity_rt_free, }; /* `set extcommunity soo COMMUNITY' */ /* For community set mechanism. */ static route_map_result_t route_set_ecommunity_soo (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct ecommunity *ecom, *old_ecom, *new_ecom; struct bgp_info *bgp_info; if (type == RMAP_BGP) { ecom = rule; bgp_info = object; if (! ecom) return RMAP_OKAY; old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; if (old_ecom) new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); else new_ecom = ecommunity_dup (ecom); bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); if (old_ecom) ecommunity_unintern (&old_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_soo_compile (const char *arg) { struct ecommunity *ecom; ecom = ecommunity_str2com (arg, ECOMMUNITY_SITE_ORIGIN, 0); if (! ecom) return NULL; return ecommunity_intern (ecom); } /* Free function for set community. */ static void route_set_ecommunity_soo_free (void *rule) { struct ecommunity *ecom = rule; ecommunity_unintern (&ecom); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { "extcommunity soo", route_set_ecommunity_soo, route_set_ecommunity_soo_compile, route_set_ecommunity_soo_free, }; /* `set 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 metric rule structure. */ struct route_map_rule_cmd route_set_origin_cmd = { "origin", route_set_origin, route_set_origin_compile, route_set_origin_free, }; /* `set atomic-aggregate' */ /* For atomic aggregate set. */ 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, }; #ifdef HAVE_IPV6 /* `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; struct bgp_info *bgp_info; if (type == RMAP_BGP) { addr = rule; bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, rule)) return RMAP_MATCH; if (bgp_info->attr->extra->mp_nexthop_len == 32 && IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, rule)) 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 }; #endif /* HAVE_IPV6 */ /* `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; } 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 metric rule structure. */ struct route_map_rule_cmd route_set_originator_id_cmd = { "originator-id", route_set_originator_id, route_set_originator_id_compile, route_set_originator_id_free, }; /* Add bgp route map rule. */ 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, "%% 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; } /* 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, "%% 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; } /* 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, "%% 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; } /* 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, "%% 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; } /* 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; /* 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[ZEBRA_FAMILY_IPV4][i].name) bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); #ifdef HAVE_IPV6 if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); #endif /* HAVE_IPV6 */ } } } DEFUN (match_peer, match_peer_cmd, "match peer (A.B.C.D|X:X::X:X)", MATCH_STR "Match peer address\n" "IPv6 address of peer\n" "IP 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" "IPv6 address of peer\n" "IP 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_community, match_community_cmd, "match community (<1-99>|<100-500>|WORD)", MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n") { return bgp_route_match_add (vty, vty->index, "community", argv[0]); } DEFUN (match_community_exact, match_community_exact_cmd, "match community (<1-99>|<100-500>|WORD) exact-match", MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n" "Do exact matching of communities\n") { int ret; char *argstr; argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, strlen (argv[0]) + strlen ("exact-match") + 2); sprintf (argstr, "%s exact-match", argv[0]); ret = bgp_route_match_add (vty, vty->index, "community", argstr); XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); return ret; } DEFUN (no_match_community, no_match_community_cmd, "no match community", NO_STR MATCH_STR "Match BGP community list\n") { return bgp_route_match_delete (vty, vty->index, "community", NULL); } ALIAS (no_match_community, no_match_community_val_cmd, "no match community (<1-99>|<100-500>|WORD)", NO_STR MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n") ALIAS (no_match_community, no_match_community_exact_cmd, "no match community (<1-99>|<100-500>|WORD) exact-match", NO_STR MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n" "Do exact matching of communities\n") DEFUN (match_ecommunity, match_ecommunity_cmd, "match extcommunity (<1-99>|<100-500>|WORD)", MATCH_STR "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" "Extended community-list number (expanded)\n" "Extended community-list name\n") { return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0]); } DEFUN (no_match_ecommunity, no_match_ecommunity_cmd, "no match extcommunity", NO_STR MATCH_STR "Match BGP/VPN extended community list\n") { return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL); } ALIAS (no_match_ecommunity, no_match_ecommunity_val_cmd, "no match extcommunity (<1-99>|<100-500>|WORD)", NO_STR MATCH_STR "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" "Extended community-list number (expanded)\n" "Extended community-list name\n") DEFUN (match_aspath, match_aspath_cmd, "match as-path WORD", MATCH_STR "Match BGP AS path list\n" "AS path access-list name\n") { return bgp_route_match_add (vty, vty->index, "as-path", argv[0]); } DEFUN (no_match_aspath, no_match_aspath_cmd, "no match as-path", NO_STR MATCH_STR "Match BGP AS path list\n") { return bgp_route_match_delete (vty, vty->index, "as-path", NULL); } ALIAS (no_match_aspath, no_match_aspath_val_cmd, "no match as-path WORD", NO_STR MATCH_STR "Match BGP AS path list\n" "AS path access-list name\n") DEFUN (match_origin, match_origin_cmd, "match origin (egp|igp|incomplete)", MATCH_STR "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") { if (strncmp (argv[0], "igp", 2) == 0) return bgp_route_match_add (vty, vty->index, "origin", "igp"); if (strncmp (argv[0], "egp", 1) == 0) return bgp_route_match_add (vty, vty->index, "origin", "egp"); if (strncmp (argv[0], "incomplete", 2) == 0) return bgp_route_match_add (vty, vty->index, "origin", "incomplete"); return CMD_WARNING; } DEFUN (no_match_origin, no_match_origin_cmd, "no match origin", NO_STR MATCH_STR "BGP origin code\n") { return bgp_route_match_delete (vty, vty->index, "origin", NULL); } ALIAS (no_match_origin, no_match_origin_val_cmd, "no match origin (egp|igp|incomplete)", NO_STR MATCH_STR "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFUN (set_ip_nexthop, set_ip_nexthop_cmd, "set ip next-hop A.B.C.D", SET_STR IP_STR "Next hop address\n" "IP address of next hop\n") { union sockunion su; int ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed Next-hop address%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (set_ip_nexthop_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") 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; } 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" "Communitly-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") { char *str; str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1); strcpy (str, argv[0]); strcpy (str + strlen (argv[0]), " delete"); bgp_route_set_add (vty, vty->index, "comm-list", str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } DEFUN (no_set_community_delete, no_set_community_delete_cmd, "no set comm-list", NO_STR SET_STR "set BGP community list (for deletion)\n") { return bgp_route_set_delete (vty, vty->index, "comm-list", NULL); } ALIAS (no_set_community_delete, no_set_community_delete_val_cmd, "no set comm-list (<1-99>|<100-500>|WORD) delete", NO_STR SET_STR "set BGP community list (for deletion)\n" "Community-list number (standard)\n" "Communitly-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFUN (set_ecommunity_rt, set_ecommunity_rt_cmd, "set extcommunity rt .ASN:nn_or_IP-address:nn", SET_STR "BGP extended community attribute\n" "Route Target 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; 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; 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") #ifdef HAVE_IPV6 DEFUN (match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD", MATCH_STR IPV6_STR "Match IPv6 address of route\n" "IPv6 access-list name\n") { return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]); } DEFUN (no_match_ipv6_address, no_match_ipv6_address_cmd, "no match ipv6 address WORD", NO_STR MATCH_STR IPV6_STR "Match IPv6 address of route\n" "IPv6 access-list name\n") { return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]); } DEFUN (match_ipv6_next_hop, match_ipv6_next_hop_cmd, "match ipv6 next-hop X:X::X:X", MATCH_STR IPV6_STR "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") { return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]); } DEFUN (no_match_ipv6_next_hop, no_match_ipv6_next_hop_cmd, "no match ipv6 next-hop X:X::X:X", NO_STR MATCH_STR IPV6_STR "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") { return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]); } DEFUN (match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, "match ipv6 address prefix-list WORD", MATCH_STR IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]); } DEFUN (no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_cmd, "no match ipv6 address prefix-list WORD", NO_STR MATCH_STR IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); } DEFUN (set_ipv6_nexthop_global, set_ipv6_nexthop_global_cmd, "set ipv6 next-hop global X:X::X:X", SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 global address\n" "IPv6 address of next hop\n") { return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]); } DEFUN (no_set_ipv6_nexthop_global, no_set_ipv6_nexthop_global_cmd, "no set ipv6 next-hop global", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 global address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL); return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]); } ALIAS (no_set_ipv6_nexthop_global, no_set_ipv6_nexthop_global_val_cmd, "no set ipv6 next-hop global X:X::X:X", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 global address\n" "IPv6 address of next hop\n") DEFUN (set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, "set ipv6 next-hop local X:X::X:X", SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") { return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]); } DEFUN (no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, "no set ipv6 next-hop local", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]); } ALIAS (no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_val_cmd, "no set ipv6 next-hop local X:X::X:X", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") #endif /* HAVE_IPV6 */ DEFUN (set_vpnv4_nexthop, set_vpnv4_nexthop_cmd, "set vpnv4 next-hop A.B.C.D", SET_STR "VPNv4 information\n" "VPNv4 next-hop address\n" "IP address of next hop\n") { return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]); } DEFUN (no_set_vpnv4_nexthop, no_set_vpnv4_nexthop_cmd, "no set vpnv4 next-hop", NO_STR SET_STR "VPNv4 information\n" "VPNv4 next-hop address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL); return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]); } ALIAS (no_set_vpnv4_nexthop, no_set_vpnv4_nexthop_val_cmd, "no set vpnv4 next-hop A.B.C.D", NO_STR SET_STR "VPNv4 information\n" "VPNv4 next-hop address\n" "IP address of next hop\n") DEFUN (set_originator_id, set_originator_id_cmd, "set originator-id A.B.C.D", SET_STR "BGP originator ID attribute\n" "IP address of originator\n") { return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]); } DEFUN (no_set_originator_id, no_set_originator_id_cmd, "no set originator-id", NO_STR SET_STR "BGP originator ID attribute\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "originator-id", NULL); return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]); } ALIAS (no_set_originator_id, no_set_originator_id_val_cmd, "no set originator-id A.B.C.D", NO_STR SET_STR "BGP originator ID attribute\n" "IP address of originator\n") 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_ip_address_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_route_source_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_route_source_prefix_list_cmd); route_map_install_match (&route_match_aspath_cmd); route_map_install_match (&route_match_community_cmd); route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); route_map_install_match (&route_match_probability_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_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); 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_community_cmd); install_element (RMAP_NODE, &match_community_exact_cmd); install_element (RMAP_NODE, &no_match_community_cmd); install_element (RMAP_NODE, &no_match_community_val_cmd); install_element (RMAP_NODE, &no_match_community_exact_cmd); install_element (RMAP_NODE, &match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_val_cmd); install_element (RMAP_NODE, &match_origin_cmd); install_element (RMAP_NODE, &no_match_origin_cmd); install_element (RMAP_NODE, &no_match_origin_val_cmd); install_element (RMAP_NODE, &match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_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, &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_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_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); #ifdef HAVE_IPV6 route_map_install_match (&route_match_ipv6_address_cmd); route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &match_ipv6_address_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_cmd); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd); install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); #endif /* HAVE_IPV6 */ /* 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-0.99.22.4/bgpd/bgp_snmp.c0000644000175000017500000006125212177450262013126 00000000000000/* 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 "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 BGPPEERMINASORIGINATIONINTERVAL 22 #define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23 #define BGPPEERINUPDATEELAPSEDTIME 24 /* BGP MIB bgpIdentifier. */ #define BGPIDENTIFIER 0 /* BGP MIB bgpRcvdPathAttrTable */ #define BGPPATHATTRPEER 1 #define BGPPATHATTRDESTNETWORK 2 #define BGPPATHATTRORIGIN 3 #define BGPPATHATTRASPATH 4 #define BGPPATHATTRNEXTHOP 5 #define BGPPATHATTRINTERASMETRIC 6 /* BGP MIB bgp4PathAttrTable. */ #define BGP4PATHATTRPEER 1 #define BGP4PATHATTRIPADDRPREFIXLEN 2 #define BGP4PATHATTRIPADDRPREFIX 3 #define BGP4PATHATTRORIGIN 4 #define BGP4PATHATTRASPATHSEGMENT 5 #define BGP4PATHATTRNEXTHOP 6 #define BGP4PATHATTRMULTIEXITDISC 7 #define BGP4PATHATTRLOCALPREF 8 #define BGP4PATHATTRATOMICAGGREGATE 9 #define BGP4PATHATTRAGGREGATORAS 10 #define BGP4PATHATTRAGGREGATORADDR 11 #define BGP4PATHATTRCALCLOCALPREF 12 #define BGP4PATHATTRBEST 13 #define BGP4PATHATTRUNKNOWN 14 /* SNMP value hack. */ #define INTEGER ASN_INTEGER #define INTEGER32 ASN_INTEGER #define COUNTER32 ASN_COUNTER #define OCTET_STRING ASN_OCTET_STR #define IPADDRESS ASN_IPADDRESS #define GAUGE32 ASN_UNSIGNED /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES /* BGP-MIB instances. */ oid bgp_oid [] = { BGP4MIB }; oid bgp_trap_oid [] = { BGP4MIB, 0 }; /* IP address 0.0.0.0. */ static struct in_addr bgp_empty_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}}, {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 22}}, {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 23}}, {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable, 3, {3, 1, 24}}, /* BGP identifier. */ {BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier, 1, {4}}, /* BGP received path attribute table. */ {BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 1}}, {BGPPATHATTRDESTNETWORK, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 2}}, {BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 3}}, {BGPPATHATTRASPATH, OCTET_STRING, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 4}}, {BGPPATHATTRNEXTHOP, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 5}}, {BGPPATHATTRINTERASMETRIC, INTEGER32, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 6}}, /* BGP-4 received path attribute table. */ {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 1}}, {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 2}}, {BGP4PATHATTRIPADDRPREFIX, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 3}}, {BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 4}}, {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable, 3, {6, 1, 5}}, {BGP4PATHATTRNEXTHOP, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 6}}, {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 7}}, {BGP4PATHATTRLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 8}}, {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 9}}, {BGP4PATHATTRAGGREGATORAS, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 10}}, {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 11}}, {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 12}}, {BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 13}}, {BGP4PATHATTRUNKNOWN, OCTET_STRING, RONLY, bgp4PathAttrTable, 3, {6, 1, 14}}, }; static u_char * bgpVersion (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static u_char version; if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Retrun BGP version. Zebra bgpd only support version 4. */ version = (0x80 >> (BGP_VERSION_4 - 1)); /* Return octet string length 1. */ *var_len = 1; return (u_char *)&version; } static u_char * bgpLocalAs (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct bgp *bgp; if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Get BGP structure. */ bgp = bgp_get_default (); if (! bgp) return NULL; return SNMP_INTEGER (bgp->as); } 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; } static struct peer * bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { struct peer *peer = NULL; int len; if (exact) { /* Check the length. */ if (*length - v->namelen != sizeof (struct in_addr)) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); peer = peer_lookup_addr_ipv4 (addr); return peer; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); peer = bgp_peer_lookup_next (addr); if (peer == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); *length = sizeof (struct in_addr) + v->namelen; return peer; } return NULL; } /* BGP write methods. */ 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 variable *v) { struct in_addr addr; struct peer *peer; long intval; size_t bigsize = SNMP_MAX_LEN; if (var_val_type != ASN_INTEGER) { return SNMP_ERR_WRONGTYPE; } if (var_val_len != sizeof (long)) { return SNMP_ERR_WRONGLENGTH; } if (! asn_parse_int(var_val, &bigsize, &var_val_type, &intval, sizeof(long))) { return SNMP_ERR_WRONGENCODING; } memset (&addr, 0, sizeof (struct in_addr)); peer = bgpPeerTable_lookup (v, name, &length, &addr, 1); if (! peer) return SNMP_ERR_NOSUCHNAME; printf ("val: %ld\n", intval); switch (v->magic) { case BGPPEERADMINSTATUS: #define BGP_PeerAdmin_stop 1 #define BGP_PeerAdmin_start 2 /* When the peer is established, */ if (intval == BGP_PeerAdmin_stop) BGP_EVENT_ADD (peer, BGP_Stop); else if (intval == BGP_PeerAdmin_start) ; /* Do nothing. */ else return SNMP_ERR_NOSUCHNAME; break; case 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 BGPPEERMINASORIGINATIONINTERVAL: peer->v_asorig = 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 BGPPEERMINASORIGINATIONINTERVAL: *write_method = write_bgpPeerTable; return SNMP_INTEGER (peer->v_asorig); break; case BGPPEERMINROUTEADVERTISEMENTINTERVAL: *write_method = write_bgpPeerTable; return SNMP_INTEGER (peer->v_routeadv); break; case BGPPEERINUPDATEELAPSEDTIME: if (peer->update_time == 0) return SNMP_INTEGER (0); else return SNMP_INTEGER (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-0.99.22.4/bgpd/bgp_snmp.h0000644000175000017500000000175712000052240013112 00000000000000/* 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-0.99.22.4/bgpd/bgp_table.c0000644000175000017500000000507312177450262013237 00000000000000/* BGP routing table Copyright (C) 1998, 2001 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "memory.h" #include "sockunion.h" #include "vty.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" void bgp_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-0.99.22.4/bgpd/bgp_table.h0000644000175000017500000001576012177450262013250 00000000000000/* 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) }; /* * 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_info * * Returns the 'info' pointer corresponding to a bgp node. */ static inline void * bgp_node_info (const struct bgp_node *node) { return node->info; } /* * bgp_node_set_info */ static inline void bgp_node_set_info (struct bgp_node *node, void *info) { node->info = info; } /* * bgp_node_prefix */ static inline struct prefix * bgp_node_prefix (struct bgp_node *node) { return &node->p; } /* * bgp_node_prefixlen */ static inline u_char bgp_node_prefixlen (struct bgp_node *node) { return bgp_node_prefix (node)->prefixlen; } /* * 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)); } #ifdef HAVE_IPV6 /* * 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)); } #endif /* HAVE_IPV6 */ 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-0.99.22.4/bgpd/bgp_vty.c0000644000175000017500000125557512177450262013011 00000000000000/* 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 "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_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" extern struct in_addr router_id_zebra; /* Utility function to get address family from current node. */ afi_t bgp_node_afi (struct vty *vty) { if (vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) return AFI_IP6; return AFI_IP; } /* Utility function to get subsequent address family from current node. */ safi_t bgp_node_safi (struct vty *vty) { if (vty->node == BGP_VPNV4_NODE) return SAFI_MPLS_VPN; if (vty->node == BGP_IPV4M_NODE || vty->node == BGP_IPV6M_NODE) return SAFI_MULTICAST; return SAFI_UNICAST; } 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); #ifdef HAVE_IPV6 else if (su->sa.sa_family == AF_INET6) ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr); #endif /* HAVE IPV6 */ if (ifp) return 1; return 0; } /* Utility function for looking up peer from VTY. */ 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 = id; bgp_router_id_set (bgp, &id); return CMD_SUCCESS; } DEFUN (no_bgp_router_id, no_bgp_router_id_cmd, "no bgp router-id", NO_STR BGP_STR "Override configured router identifier\n") { int ret; struct in_addr id; struct bgp *bgp; bgp = vty->index; if (argc == 1) { ret = inet_aton (argv[0], &id); if (! ret) { vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); return CMD_WARNING; } if (! IPV4_ADDR_SAME (&bgp->router_id_static, &id)) { vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); return CMD_WARNING; } } bgp->router_id_static.s_addr = 0; bgp_router_id_set (bgp, &router_id_zebra); 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; 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 <1-255>", "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 <1-255>", "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 <1-255>", 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 <1-255>", 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 (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_cmd, "no bgp graceful-restart stalepath-time", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n") { struct bgp *bgp; bgp = vty->index; if (! bgp) return CMD_WARNING; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; return CMD_SUCCESS; } ALIAS (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_val_cmd, "no bgp graceful-restart stalepath-time <1-3600>", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") /* "bgp fast-external-failover" configuration. */ DEFUN (bgp_fast_external_failover, bgp_fast_external_failover_cmd, "bgp fast-external-failover", BGP_STR "Immediately reset session if a link to a directly connected external peer goes down\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); return CMD_SUCCESS; } DEFUN (no_bgp_fast_external_failover, no_bgp_fast_external_failover_cmd, "no bgp fast-external-failover", NO_STR BGP_STR "Immediately reset session if a link to a directly connected external peer goes down\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); return CMD_SUCCESS; } /* "bgp enforce-first-as" configuration. */ DEFUN (bgp_enforce_first_as, bgp_enforce_first_as_cmd, "bgp enforce-first-as", BGP_STR "Enforce the first AS for EBGP routes\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 log-neighbor-changes" configuration. */ DEFUN (bgp_log_neighbor_changes, bgp_log_neighbor_changes_cmd, "bgp log-neighbor-changes", "BGP specific commands\n" "Log neighbor up/down and reset reason\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); return CMD_SUCCESS; } DEFUN (no_bgp_log_neighbor_changes, no_bgp_log_neighbor_changes_cmd, "no bgp log-neighbor-changes", NO_STR "BGP specific commands\n" "Log neighbor up/down and reset reason\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); return CMD_SUCCESS; } /* "bgp bestpath med" configuration. */ DEFUN (bgp_bestpath_med, bgp_bestpath_med_cmd, "bgp bestpath med (confed|missing-as-worst)", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; if (strncmp (argv[0], "confed", 1) == 0) bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); else bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } DEFUN (bgp_bestpath_med2, bgp_bestpath_med2_cmd, "bgp bestpath med confed missing-as-worst", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } ALIAS (bgp_bestpath_med2, bgp_bestpath_med3_cmd, "bgp bestpath med missing-as-worst confed", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") DEFUN (no_bgp_bestpath_med, no_bgp_bestpath_med_cmd, "no bgp bestpath med (confed|missing-as-worst)", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; if (strncmp (argv[0], "confed", 1) == 0) bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); else bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_med2, no_bgp_bestpath_med2_cmd, "no bgp bestpath med confed missing-as-worst", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } ALIAS (no_bgp_bestpath_med2, no_bgp_bestpath_med3_cmd, "no bgp bestpath med missing-as-worst confed", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") /* "no bgp default ipv4-unicast". */ DEFUN (no_bgp_default_ipv4_unicast, no_bgp_default_ipv4_unicast_cmd, "no bgp default ipv4-unicast", NO_STR "BGP specific commands\n" "Configure BGP defaults\n" "Activate ipv4-unicast for a peer by default\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_NO_DEFAULT_IPV4); return CMD_SUCCESS; } DEFUN (bgp_default_ipv4_unicast, bgp_default_ipv4_unicast_cmd, "bgp default ipv4-unicast", "BGP specific commands\n" "Configure BGP defaults\n" "Activate ipv4-unicast for a peer by default\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4); return CMD_SUCCESS; } /* "bgp import-check" configuration. */ DEFUN (bgp_network_import_check, bgp_network_import_check_cmd, "bgp network import-check", "BGP specific commands\n" "BGP network command\n" "Check BGP network route exists in IGP\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); return CMD_SUCCESS; } DEFUN (no_bgp_network_import_check, no_bgp_network_import_check_cmd, "no bgp network import-check", NO_STR "BGP specific commands\n" "BGP network command\n" "Check BGP network route exists in IGP\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); return CMD_SUCCESS; } DEFUN (bgp_default_local_preference, bgp_default_local_preference_cmd, "bgp default local-preference <0-4294967295>", "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") { struct bgp *bgp; u_int32_t local_pref; bgp = vty->index; VTY_GET_INTEGER ("local preference", local_pref, argv[0]); bgp_default_local_preference_set (bgp, local_pref); return CMD_SUCCESS; } DEFUN (no_bgp_default_local_preference, no_bgp_default_local_preference_cmd, "no bgp default local-preference", NO_STR "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n") { struct bgp *bgp; bgp = vty->index; bgp_default_local_preference_unset (bgp); return CMD_SUCCESS; } ALIAS (no_bgp_default_local_preference, no_bgp_default_local_preference_val_cmd, "no bgp default local-preference <0-4294967295>", NO_STR "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") static int peer_remote_as_vty (struct vty *vty, 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", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Disable the next hop calculation for this neighbor\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); } DEFUN (no_neighbor_nexthop_self, no_neighbor_nexthop_self_cmd, NO_NEIGHBOR_CMD2 "next-hop-self", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Disable the next hop calculation for this neighbor\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF); } /* neighbor remove-private-AS. */ DEFUN (neighbor_remove_private_as, neighbor_remove_private_as_cmd, NEIGHBOR_CMD2 "remove-private-AS", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Remove private AS number from outbound updates\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REMOVE_PRIVATE_AS); } DEFUN (no_neighbor_remove_private_as, no_neighbor_remove_private_as_cmd, NO_NEIGHBOR_CMD2 "remove-private-AS", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Remove private AS number from outbound updates\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REMOVE_PRIVATE_AS); } /* neighbor send-community. */ DEFUN (neighbor_send_community, neighbor_send_community_cmd, NEIGHBOR_CMD2 "send-community", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); } DEFUN (no_neighbor_send_community, no_neighbor_send_community_cmd, NO_NEIGHBOR_CMD2 "send-community", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); } /* neighbor send-community extended. */ DEFUN (neighbor_send_community_type, neighbor_send_community_type_cmd, NEIGHBOR_CMD2 "send-community (both|extended|standard)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n") { if (strncmp (argv[1], "s", 1) == 0) return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); if (strncmp (argv[1], "e", 1) == 0) return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY| PEER_FLAG_SEND_EXT_COMMUNITY)); } DEFUN (no_neighbor_send_community_type, no_neighbor_send_community_type_cmd, NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n") { if (strncmp (argv[1], "s", 1) == 0) return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); if (strncmp (argv[1], "e", 1) == 0) return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY)); } /* neighbor soft-reconfig. */ DEFUN (neighbor_soft_reconfiguration, neighbor_soft_reconfiguration_cmd, NEIGHBOR_CMD2 "soft-reconfiguration inbound", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Per neighbor soft reconfiguration\n" "Allow inbound soft reconfiguration for this neighbor\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SOFT_RECONFIG); } DEFUN (no_neighbor_soft_reconfiguration, no_neighbor_soft_reconfiguration_cmd, NO_NEIGHBOR_CMD2 "soft-reconfiguration inbound", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Per neighbor soft reconfiguration\n" "Allow inbound soft reconfiguration for this neighbor\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SOFT_RECONFIG); } DEFUN (neighbor_route_reflector_client, neighbor_route_reflector_client_cmd, NEIGHBOR_CMD2 "route-reflector-client", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Reflector client\n") { struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REFLECTOR_CLIENT); } DEFUN (no_neighbor_route_reflector_client, no_neighbor_route_reflector_client_cmd, NO_NEIGHBOR_CMD2 "route-reflector-client", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Reflector client\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REFLECTOR_CLIENT); } 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_unset (peer)); } /* 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) { int ret; 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); ret = peer_weight_set (peer, weight); return CMD_SUCCESS; } 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; peer_weight_unset (peer); return CMD_SUCCESS; } DEFUN (neighbor_weight, neighbor_weight_cmd, NEIGHBOR_CMD2 "weight <0-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set default weight for routes from this neighbor\n" "default weight\n") { return peer_weight_set_vty (vty, argv[0], argv[1]); } 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) { int ret; struct peer *peer; u_int32_t connect; peer = peer_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("Connect time", connect, time_str, 0, 65535); ret = peer_timers_connect_set (peer, connect); return CMD_SUCCESS; } static int peer_timers_connect_unset_vty (struct vty *vty, const char *ip_str) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; ret = peer_timers_connect_unset (peer); return CMD_SUCCESS; } DEFUN (neighbor_timers_connect, neighbor_timers_connect_cmd, NEIGHBOR_CMD "timers connect <0-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR "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_CMD "timers connect", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "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_CMD "timers connect <0-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "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_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; if (time_str) VTY_GET_INTEGER_RANGE ("advertise interval", routeadv, time_str, 0, 600); if (set) ret = peer_advertise_interval_set (peer, routeadv); else ret = peer_advertise_interval_unset (peer); return CMD_SUCCESS; } DEFUN (neighbor_advertise_interval, neighbor_advertise_interval_cmd, NEIGHBOR_CMD "advertisement-interval <0-600>", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n" "time in seconds\n") { return peer_advertise_interval_vty (vty, argv[0], argv[1], 1); } DEFUN (no_neighbor_advertise_interval, no_neighbor_advertise_interval_cmd, NO_NEIGHBOR_CMD "advertisement-interval", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n") { return peer_advertise_interval_vty (vty, argv[0], NULL, 0); } ALIAS (no_neighbor_advertise_interval, no_neighbor_advertise_interval_val_cmd, NO_NEIGHBOR_CMD "advertisement-interval <0-600>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n" "time in seconds\n") /* neighbor interface */ 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 CMD_SUCCESS; } DEFUN (neighbor_interface, neighbor_interface_cmd, NEIGHBOR_CMD "interface WORD", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Interface\n" "Interface name\n") { return peer_interface_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_interface, no_neighbor_interface_cmd, NO_NEIGHBOR_CMD "interface WORD", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Interface\n" "Interface name\n") { return peer_interface_vty (vty, argv[0], NULL); } /* Set distribute list to the peer. */ 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 occurances of AS number\n") DEFUN (no_neighbor_allowas_in, no_neighbor_allowas_in_cmd, NO_NEIGHBOR_CMD2 "allowas-in", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "allow local ASN appears in aspath attribute\n") { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_allowas_in_unset (peer, bgp_node_afi (vty), bgp_node_safi (vty)); return bgp_vty_return (vty, ret); } 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_unset (peer)); } /* 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 (exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_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; } 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_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" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_soft_out, clear_ip_bgp_all_out_cmd, "clear ip bgp * out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig outbound update\n") ALIAS (clear_ip_bgp_all_soft_out, clear_ip_bgp_instance_all_soft_out_cmd, "clear ip bgp view WORD * soft out", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_all_ipv4_soft_out, clear_ip_bgp_all_ipv4_soft_out_cmd, "clear ip bgp * ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_ipv4_soft_out, clear_ip_bgp_all_ipv4_out_cmd, "clear ip bgp * ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, clear_ip_bgp_instance_all_ipv4_soft_out_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } DEFUN (clear_ip_bgp_all_vpnv4_soft_out, clear_ip_bgp_all_vpnv4_soft_out_cmd, "clear ip bgp * vpnv4 unicast soft out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_vpnv4_soft_out, clear_ip_bgp_all_vpnv4_out_cmd, "clear ip bgp * vpnv4 unicast out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_all_soft_out, clear_bgp_all_soft_out_cmd, "clear bgp * soft out", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_bgp_all_soft_out, clear_bgp_instance_all_soft_out_cmd, "clear bgp view WORD * soft out", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_all_soft_out, clear_bgp_all_out_cmd, "clear bgp * out", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_all_soft_out, clear_bgp_ipv6_all_soft_out_cmd, "clear bgp ipv6 * soft out", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_all_soft_out, clear_bgp_ipv6_all_out_cmd, "clear bgp ipv6 * out", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_soft_out, clear_ip_bgp_peer_soft_out_cmd, "clear ip bgp A.B.C.D soft out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_soft_out, clear_ip_bgp_peer_out_cmd, "clear ip bgp A.B.C.D out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_ipv4_soft_out, clear_ip_bgp_peer_ipv4_soft_out_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_ipv4_soft_out, clear_ip_bgp_peer_ipv4_out_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, clear_ip_bgp_peer_vpnv4_soft_out_cmd, "clear ip bgp A.B.C.D vpnv4 unicast soft out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, clear_ip_bgp_peer_vpnv4_out_cmd, "clear ip bgp A.B.C.D vpnv4 unicast out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_peer_soft_out, clear_bgp_peer_soft_out_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft out", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_bgp_peer_soft_out, clear_bgp_ipv6_peer_soft_out_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_soft_out, clear_bgp_peer_out_cmd, "clear bgp (A.B.C.D|X:X::X:X) out", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_soft_out, clear_bgp_ipv6_peer_out_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_group_soft_out, clear_ip_bgp_peer_group_soft_out_cmd, "clear ip bgp peer-group WORD soft out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_group_soft_out, clear_ip_bgp_peer_group_out_cmd, "clear ip bgp peer-group WORD out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, clear_ip_bgp_peer_group_ipv4_soft_out_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out, clear_ip_bgp_peer_group_ipv4_out_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_peer_group_soft_out, clear_bgp_peer_group_soft_out_cmd, "clear bgp peer-group WORD soft out", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_ipv6_peer_group_soft_out_cmd, "clear bgp ipv6 peer-group WORD soft out", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_peer_group_out_cmd, "clear bgp peer-group WORD out", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_ipv6_peer_group_out_cmd, "clear bgp ipv6 peer-group WORD out", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_external_soft_out, clear_ip_bgp_external_soft_out_cmd, "clear ip bgp external soft out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_external_soft_out, clear_ip_bgp_external_out_cmd, "clear ip bgp external out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_external_ipv4_soft_out, clear_ip_bgp_external_ipv4_soft_out_cmd, "clear ip bgp external ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_external_ipv4_soft_out, clear_ip_bgp_external_ipv4_out_cmd, "clear ip bgp external ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_external_soft_out, clear_bgp_external_soft_out_cmd, "clear bgp external soft out", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_bgp_external_soft_out, clear_bgp_ipv6_external_soft_out_cmd, "clear bgp ipv6 external soft out", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_external_soft_out, clear_bgp_external_out_cmd, "clear bgp external out", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_external_soft_out, clear_bgp_ipv6_external_out_cmd, "clear bgp ipv6 external WORD out", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_as_soft_out, clear_ip_bgp_as_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " soft out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_soft_out, clear_ip_bgp_as_out_cmd, "clear ip bgp " CMD_AS_RANGE " out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_as_ipv4_soft_out, clear_ip_bgp_as_ipv4_soft_out_cmd, "clear ip bgp " 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" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_ipv4_soft_out, clear_ip_bgp_as_ipv4_out_cmd, "clear ip bgp " 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" "Soft reconfig outbound update\n") 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" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_vpnv4_soft_out, clear_ip_bgp_as_vpnv4_out_cmd, "clear ip bgp " 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" "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" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_bgp_as_soft_out, clear_bgp_ipv6_as_soft_out_cmd, "clear bgp ipv6 " CMD_AS_RANGE " soft out", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_as_soft_out, clear_bgp_as_out_cmd, "clear bgp " CMD_AS_RANGE " out", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_as_soft_out, clear_bgp_ipv6_as_out_cmd, "clear bgp ipv6 " CMD_AS_RANGE " out", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig outbound update\n") /* Inbound soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft_in, clear_ip_bgp_all_soft_in_cmd, "clear ip bgp * soft in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_soft_in, clear_ip_bgp_instance_all_soft_in_cmd, "clear ip bgp view WORD * soft in", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_ip_bgp_all_soft_in, clear_ip_bgp_all_in_cmd, "clear ip bgp * in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_all_in_prefix_filter, clear_ip_bgp_all_in_prefix_filter_cmd, "clear ip bgp * in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (argc== 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } ALIAS (clear_ip_bgp_all_in_prefix_filter, clear_ip_bgp_instance_all_in_prefix_filter_cmd, "clear ip bgp view WORD * in prefix-filter", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_all_ipv4_soft_in, clear_ip_bgp_all_ipv4_soft_in_cmd, "clear ip bgp * ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_ipv4_soft_in, clear_ip_bgp_all_ipv4_in_cmd, "clear ip bgp * ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, clear_ip_bgp_instance_all_ipv4_soft_in_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter, clear_ip_bgp_all_ipv4_in_prefix_filter_cmd, "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter, clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_ip_bgp_all_vpnv4_soft_in, clear_ip_bgp_all_vpnv4_soft_in_cmd, "clear ip bgp * vpnv4 unicast soft in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_vpnv4_soft_in, clear_ip_bgp_all_vpnv4_in_cmd, "clear ip bgp * vpnv4 unicast in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_all_soft_in, clear_bgp_all_soft_in_cmd, "clear bgp * soft in", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_bgp_all_soft_in, clear_bgp_instance_all_soft_in_cmd, "clear bgp view WORD * soft in", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_all_soft_in, clear_bgp_ipv6_all_soft_in_cmd, "clear bgp ipv6 * soft in", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_all_soft_in, clear_bgp_all_in_cmd, "clear bgp * in", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_all_soft_in, clear_bgp_ipv6_all_in_cmd, "clear bgp ipv6 * in", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_all_in_prefix_filter, clear_bgp_all_in_prefix_filter_cmd, "clear bgp * in prefix-filter", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } ALIAS (clear_bgp_all_in_prefix_filter, clear_bgp_ipv6_all_in_prefix_filter_cmd, "clear bgp ipv6 * in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_peer_soft_in, clear_ip_bgp_peer_soft_in_cmd, "clear ip bgp A.B.C.D soft in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_soft_in, clear_ip_bgp_peer_in_cmd, "clear ip bgp A.B.C.D in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_in_prefix_filter, clear_ip_bgp_peer_in_prefix_filter_cmd, "clear ip bgp A.B.C.D in prefix-filter", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_peer_ipv4_soft_in, clear_ip_bgp_peer_ipv4_soft_in_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_ipv4_soft_in, clear_ip_bgp_peer_ipv4_in_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_peer_vpnv4_soft_in, clear_ip_bgp_peer_vpnv4_soft_in_cmd, "clear ip bgp A.B.C.D vpnv4 unicast soft in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, clear_ip_bgp_peer_vpnv4_in_cmd, "clear ip bgp A.B.C.D vpnv4 unicast in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_peer_soft_in, clear_bgp_peer_soft_in_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft in", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_bgp_peer_soft_in, clear_bgp_ipv6_peer_soft_in_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_soft_in, clear_bgp_peer_in_cmd, "clear bgp (A.B.C.D|X:X::X:X) in", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_soft_in, clear_bgp_ipv6_peer_in_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_peer_in_prefix_filter, clear_bgp_peer_in_prefix_filter_cmd, "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } ALIAS (clear_bgp_peer_in_prefix_filter, clear_bgp_ipv6_peer_in_prefix_filter_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") DEFUN (clear_ip_bgp_peer_group_soft_in, clear_ip_bgp_peer_group_soft_in_cmd, "clear ip bgp peer-group WORD soft in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_group_soft_in, clear_ip_bgp_peer_group_in_cmd, "clear ip bgp peer-group WORD in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, clear_ip_bgp_peer_group_in_prefix_filter_cmd, "clear ip bgp peer-group WORD in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in, clear_ip_bgp_peer_group_ipv4_soft_in_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in, clear_ip_bgp_peer_group_ipv4_in_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_bgp_peer_group_soft_in, clear_bgp_peer_group_soft_in_cmd, "clear bgp peer-group WORD soft in", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_ipv6_peer_group_soft_in_cmd, "clear bgp ipv6 peer-group WORD soft in", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_peer_group_in_cmd, "clear bgp peer-group WORD in", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_ipv6_peer_group_in_cmd, "clear bgp ipv6 peer-group WORD in", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_peer_group_in_prefix_filter, clear_bgp_peer_group_in_prefix_filter_cmd, "clear bgp peer-group WORD in prefix-filter", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } ALIAS (clear_bgp_peer_group_in_prefix_filter, clear_bgp_ipv6_peer_group_in_prefix_filter_cmd, "clear bgp ipv6 peer-group WORD in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_external_soft_in, clear_ip_bgp_external_soft_in_cmd, "clear ip bgp external soft in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_external_soft_in, clear_ip_bgp_external_in_cmd, "clear ip bgp external in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_external_in_prefix_filter, clear_ip_bgp_external_in_prefix_filter_cmd, "clear ip bgp external in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_ip_bgp_external_ipv4_soft_in, clear_ip_bgp_external_ipv4_soft_in_cmd, "clear ip bgp external ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_external_ipv4_soft_in, clear_ip_bgp_external_ipv4_in_cmd, "clear ip bgp external ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd, "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_bgp_external_soft_in, clear_bgp_external_soft_in_cmd, "clear bgp external soft in", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_bgp_external_soft_in, clear_bgp_ipv6_external_soft_in_cmd, "clear bgp ipv6 external soft in", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_external_soft_in, clear_bgp_external_in_cmd, "clear bgp external in", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_external_soft_in, clear_bgp_ipv6_external_in_cmd, "clear bgp ipv6 external WORD in", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_external_in_prefix_filter, clear_bgp_external_in_prefix_filter_cmd, "clear bgp external in prefix-filter", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } ALIAS (clear_bgp_external_in_prefix_filter, clear_bgp_ipv6_external_in_prefix_filter_cmd, "clear bgp ipv6 external in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_as_soft_in, clear_ip_bgp_as_soft_in_cmd, "clear ip bgp " CMD_AS_RANGE " soft in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_soft_in, clear_ip_bgp_as_in_cmd, "clear ip bgp " CMD_AS_RANGE " in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_as_in_prefix_filter, clear_ip_bgp_as_in_prefix_filter_cmd, "clear ip bgp " CMD_AS_RANGE " in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_as_ipv4_soft_in, clear_ip_bgp_as_ipv4_soft_in_cmd, "clear ip bgp " 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" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_ipv4_soft_in, clear_ip_bgp_as_ipv4_in_cmd, "clear ip bgp " 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" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, "clear ip bgp " 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" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_as_vpnv4_soft_in, clear_ip_bgp_as_vpnv4_soft_in_cmd, "clear ip bgp " 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" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_vpnv4_soft_in, clear_ip_bgp_as_vpnv4_in_cmd, "clear ip bgp " 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" "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" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_bgp_as_soft_in, clear_bgp_ipv6_as_soft_in_cmd, "clear bgp ipv6 " CMD_AS_RANGE " soft in", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_as_soft_in, clear_bgp_as_in_cmd, "clear bgp " CMD_AS_RANGE " in", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_as_soft_in, clear_bgp_ipv6_as_in_cmd, "clear bgp ipv6 " CMD_AS_RANGE " in", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_as_in_prefix_filter, clear_bgp_as_in_prefix_filter_cmd, "clear bgp " CMD_AS_RANGE " in prefix-filter", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } ALIAS (clear_bgp_as_in_prefix_filter, clear_bgp_ipv6_as_in_prefix_filter_cmd, "clear bgp ipv6 " CMD_AS_RANGE " in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") /* Both soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft, clear_ip_bgp_all_soft_cmd, "clear ip bgp * soft", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); } ALIAS (clear_ip_bgp_all_soft, clear_ip_bgp_instance_all_soft_cmd, "clear ip bgp view WORD * soft", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_all_ipv4_soft, clear_ip_bgp_all_ipv4_soft_cmd, "clear ip bgp * ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_ip_bgp_instance_all_ipv4_soft, clear_ip_bgp_instance_all_ipv4_soft_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_ip_bgp_all_vpnv4_soft, clear_ip_bgp_all_vpnv4_soft_cmd, "clear ip bgp * vpnv4 unicast soft", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_all_soft, clear_bgp_all_soft_cmd, "clear bgp * soft", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_all_soft, clear_bgp_instance_all_soft_cmd, "clear bgp view WORD * soft", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n") ALIAS (clear_bgp_all_soft, clear_bgp_ipv6_all_soft_cmd, "clear bgp ipv6 * soft", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_peer_soft, clear_ip_bgp_peer_soft_cmd, "clear ip bgp A.B.C.D soft", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_ipv4_soft, clear_ip_bgp_peer_ipv4_soft_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_vpnv4_soft, clear_ip_bgp_peer_vpnv4_soft_cmd, "clear ip bgp A.B.C.D vpnv4 unicast soft", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_peer_soft, clear_bgp_peer_soft_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_peer_soft, clear_bgp_ipv6_peer_soft_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_peer_group_soft, clear_ip_bgp_peer_group_soft_cmd, "clear ip bgp peer-group WORD soft", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_group_ipv4_soft, clear_ip_bgp_peer_group_ipv4_soft_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_peer_group_soft, clear_bgp_peer_group_soft_cmd, "clear bgp peer-group WORD soft", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_peer_group_soft, clear_bgp_ipv6_peer_group_soft_cmd, "clear bgp ipv6 peer-group WORD soft", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_external_soft, clear_ip_bgp_external_soft_cmd, "clear ip bgp external soft", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_ip_bgp_external_ipv4_soft, clear_ip_bgp_external_ipv4_soft_cmd, "clear ip bgp external ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_bgp_external_soft, clear_bgp_external_soft_cmd, "clear bgp external soft", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); } ALIAS (clear_bgp_external_soft, clear_bgp_ipv6_external_soft_cmd, "clear bgp ipv6 external soft", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_as_soft, clear_ip_bgp_as_soft_cmd, "clear ip bgp " CMD_AS_RANGE " soft", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_as_ipv4_soft, clear_ip_bgp_as_ipv4_soft_cmd, "clear ip bgp " 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" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL,AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_as_vpnv4_soft, clear_ip_bgp_as_vpnv4_soft_cmd, "clear ip bgp " 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" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_as_soft, clear_bgp_as_soft_cmd, "clear bgp " CMD_AS_RANGE " soft", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_as_soft, clear_bgp_ipv6_as_soft_cmd, "clear bgp ipv6 " CMD_AS_RANGE " soft", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n") /* RS-client soft reconfiguration. */ #ifdef HAVE_IPV6 DEFUN (clear_bgp_all_rsclient, clear_bgp_all_rsclient_cmd, "clear bgp * rsclient", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig for rsclient RIB\n") { 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" "Soft reconfig for rsclient RIB\n") 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" "Soft reconfig for rsclient RIB\n") 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" "Soft reconfig for rsclient RIB\n") #endif /* HAVE_IPV6 */ 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" "Soft reconfig for rsclient RIB\n") { 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" "Soft reconfig for rsclient RIB\n") #ifdef HAVE_IPV6 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" "Soft reconfig for rsclient RIB\n") { 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" "Soft reconfig for rsclient RIB\n") 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" "Soft reconfig for rsclient RIB\n") 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" "Soft reconfig for rsclient RIB\n") #endif /* HAVE_IPV6 */ 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" "Soft reconfig for rsclient RIB\n") { 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" "Soft reconfig for rsclient RIB\n") 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_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; 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 %4lu ", 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, (unsigned long) peer->obuf->count); vty_out (vty, "%8s", peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); if (peer->status == Established) { vty_out (vty, " %8ld", peer->pcount[afi][safi]); } else { if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " Idle (Admin)"); else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) vty_out (vty, " Idle (PfxCt)"); else vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, peer->status)); } vty_out (vty, "%s", VTY_NEWLINE); } } if (count) vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE, count, VTY_NEWLINE); else vty_out (vty, "No %s neighbor is configured%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); return CMD_SUCCESS; } 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); } ALIAS (show_ip_bgp_ipv4_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") 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); } ALIAS (show_ip_bgp_instance_ipv4_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") DEFUN (show_ip_bgp_vpnv4_all_summary, show_ip_bgp_vpnv4_all_summary_cmd, "show ip bgp vpnv4 all summary", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); } DEFUN (show_ip_bgp_vpnv4_rd_summary, show_ip_bgp_vpnv4_rd_summary_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Summary of BGP neighbor status\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); } #ifdef HAVE_IPV6 DEFUN (show_bgp_summary, show_bgp_summary_cmd, "show bgp summary", SHOW_STR BGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } DEFUN (show_bgp_instance_summary, show_bgp_instance_summary_cmd, "show bgp view WORD summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_summary, show_bgp_ipv6_summary_cmd, "show bgp ipv6 summary", SHOW_STR BGP_STR "Address family\n" "Summary of BGP neighbor status\n") ALIAS (show_bgp_instance_summary, show_bgp_instance_ipv6_summary_cmd, "show bgp view WORD ipv6 summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Summary of BGP neighbor status\n") 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); } #endif /* HAVE_IPV6 */ 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 "VPNv4 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6 Multicast"; else return "Unknown"; } /* Show BGP peer's information. */ enum show_type { show_all, show_peer }; 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)) { vty_out (vty, " Community attribute sent to this neighbor"); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, "(both)%s", VTY_NEWLINE); else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, "(extended)%s", VTY_NEWLINE); else vty_out (vty, "(standard)%s", VTY_NEWLINE); } if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) { vty_out (vty, " Default information originate,"); if (p->default_rmap[afi][safi].name) vty_out (vty, " default route-map %s%s,", p->default_rmap[afi][safi].map ? "*" : "", p->default_rmap[afi][safi].name); if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) vty_out (vty, " default sent%s", VTY_NEWLINE); else vty_out (vty, " default not sent%s", VTY_NEWLINE); } if (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; 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] #ifdef HAVE_IPV6 || p->afc_adv[AFI_IP6][SAFI_UNICAST] || p->afc_recv[AFI_IP6][SAFI_UNICAST] || p->afc_adv[AFI_IP6][SAFI_MULTICAST] || p->afc_recv[AFI_IP6][SAFI_MULTICAST] #endif /* HAVE_IPV6 */ || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE); /* 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 */ if (p->sort != BGP_PEER_IBGP) { if (p->gtsm_hops > 0) vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", p->gtsm_hops, VTY_NEWLINE); else if (p->ttl > 1) vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", p->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); #ifdef HAVE_IPV6 vty_out (vty, "Nexthop global: %s%s", inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ), VTY_NEWLINE); vty_out (vty, "Nexthop local: %s%s", inet_ntop (AF_INET6, &p->nexthop.v6_local, buf1, BUFSIZ), VTY_NEWLINE); vty_out (vty, "BGP connection: %s%s", p->shared_network ? "shared network" : "non shared network", VTY_NEWLINE); #endif /* HAVE_IPV6 */ } /* Timer information. */ if (p->t_start) vty_out (vty, "Next start timer due in %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_neighbors_cmd, "show bgp neighbors", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n") ALIAS (show_ip_bgp_neighbors, show_bgp_ipv6_neighbors_cmd, "show bgp ipv6 neighbors", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") DEFUN (show_ip_bgp_neighbors_peer, show_ip_bgp_neighbors_peer_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") { return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); } ALIAS (show_ip_bgp_neighbors_peer, show_ip_bgp_ipv4_neighbors_peer_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_ip_bgp_vpnv4_all_neighbors_peer_cmd, "show ip bgp vpnv4 all neighbors A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_ip_bgp_vpnv4_rd_neighbors_peer_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_bgp_neighbors_peer_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_bgp_ipv6_neighbors_peer_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFUN (show_ip_bgp_instance_neighbors, show_ip_bgp_instance_neighbors_cmd, "show ip bgp view WORD neighbors", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") { return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); } ALIAS (show_ip_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") 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]); } ALIAS (show_ip_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") ALIAS (show_ip_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_ip_bgp_paths, show_ip_bgp_paths_cmd, "show ip bgp paths", SHOW_STR IP_STR BGP_STR "Path information\n") { vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); aspath_print_all_vty (vty); return CMD_SUCCESS; } DEFUN (show_ip_bgp_ipv4_paths, show_ip_bgp_ipv4_paths_cmd, "show ip bgp ipv4 (unicast|multicast) paths", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Path information\n") { vty_out (vty, "Address Refcnt Path\r\n"); aspath_print_all_vty (vty); return CMD_SUCCESS; } #include "hash.h" 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", backet, com->refcnt, community_str (com), VTY_NEWLINE); } /* Show BGP's community internal data. */ DEFUN (show_ip_bgp_community_info, show_ip_bgp_community_info_cmd, "show ip bgp community-info", SHOW_STR IP_STR BGP_STR "List all bgp community information\n") { vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE); hash_iterate (community_hash (), (void (*) (struct hash_backet *, void *)) community_show_all_iterator, vty); return CMD_SUCCESS; } DEFUN (show_ip_bgp_attr_info, show_ip_bgp_attr_info_cmd, "show ip bgp attribute-info", SHOW_STR IP_STR BGP_STR "List all bgp attribute information\n") { attr_show_all (vty); return CMD_SUCCESS; } 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, "%11d ", 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") #ifdef HAVE_IPV6 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") { return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } 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") { return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_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") ALIAS (show_bgp_instance_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") 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 "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") #endif /* HAVE IPV6 */ /* 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); } DEFUN (no_bgp_redistribute_ipv4_rmap, 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") { 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_routemap_unset (vty->index, AFI_IP, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv4_metric, 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") { 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_metric_unset (vty->index, AFI_IP, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_rmap_metric_cmd, "no redistribute " 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") { 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_metric_unset (vty->index, AFI_IP, type); bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); return CMD_SUCCESS; } ALIAS (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_metric_rmap_cmd, "no redistribute " 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") #ifdef HAVE_IPV6 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); } DEFUN (no_bgp_redistribute_ipv6_rmap, 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") { 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_routemap_unset (vty->index, AFI_IP6, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv6_metric, 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") { 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_metric_unset (vty->index, AFI_IP6, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_rmap_metric_cmd, "no redistribute " 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") { 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_metric_unset (vty->index, AFI_IP6, type); bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); return CMD_SUCCESS; } ALIAS (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_metric_rmap_cmd, "no redistribute " 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") #endif /* HAVE_IPV6 */ 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 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 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); /* "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_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); /* "timers bgp" commands. */ install_element (BGP_NODE, &bgp_timers_cmd); install_element (BGP_NODE, &no_bgp_timers_cmd); install_element (BGP_NODE, &no_bgp_timers_arg_cmd); /* "bgp client-to-client reflection" commands */ install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd); install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd); /* "bgp always-compare-med" commands */ install_element (BGP_NODE, &bgp_always_compare_med_cmd); install_element (BGP_NODE, &no_bgp_always_compare_med_cmd); /* "bgp deterministic-med" commands */ install_element (BGP_NODE, &bgp_deterministic_med_cmd); install_element (BGP_NODE, &no_bgp_deterministic_med_cmd); /* "bgp graceful-restart" commands */ install_element (BGP_NODE, &bgp_graceful_restart_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_cmd); install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd); /* "bgp fast-external-failover" commands */ install_element (BGP_NODE, &bgp_fast_external_failover_cmd); install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd); /* "bgp enforce-first-as" commands */ install_element (BGP_NODE, &bgp_enforce_first_as_cmd); install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd); /* "bgp bestpath compare-routerid" commands */ install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd); install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd); /* "bgp bestpath 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 log-neighbor-changes" commands */ install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd); install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd); /* "bgp bestpath med" commands */ install_element (BGP_NODE, &bgp_bestpath_med_cmd); install_element (BGP_NODE, &bgp_bestpath_med2_cmd); install_element (BGP_NODE, &bgp_bestpath_med3_cmd); install_element (BGP_NODE, &no_bgp_bestpath_med_cmd); install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd); install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd); /* "no bgp default ipv4-unicast" commands. */ install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd); install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd); /* "bgp network import-check" commands. */ install_element (BGP_NODE, &bgp_network_import_check_cmd); install_element (BGP_NODE, &no_bgp_network_import_check_cmd); /* "bgp default local-preference" commands. */ install_element (BGP_NODE, &bgp_default_local_preference_cmd); install_element (BGP_NODE, &no_bgp_default_local_preference_cmd); install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd); /* "neighbor remote-as" commands. */ install_element (BGP_NODE, &neighbor_remote_as_cmd); install_element (BGP_NODE, &no_neighbor_cmd); install_element (BGP_NODE, &no_neighbor_remote_as_cmd); /* "neighbor peer-group" commands. */ install_element (BGP_NODE, &neighbor_peer_group_cmd); install_element (BGP_NODE, &no_neighbor_peer_group_cmd); install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd); /* "neighbor local-as" commands. */ install_element (BGP_NODE, &neighbor_local_as_cmd); install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd); install_element (BGP_NODE, &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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* "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); /* address-family commands. */ install_element (BGP_NODE, &address_family_ipv4_cmd); install_element (BGP_NODE, &address_family_ipv4_safi_cmd); #ifdef HAVE_IPV6 install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_safi_cmd); #endif /* HAVE_IPV6 */ install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); /* "clear ip bgp commands" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd); install_element (ENABLE_NODE, &clear_bgp_external_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd); install_element (ENABLE_NODE, &clear_bgp_as_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft in" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_all_in_cmd); install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_external_in_cmd); install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_as_in_cmd); install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft out" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_all_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd); install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_external_out_cmd); install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_as_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd); #endif /* HAVE_IPV6 */ /* "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); #ifdef HAVE_IPV6 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); #endif /* HAVE_IPV6 */ /* "show ip bgp summary" commands. */ install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_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); #endif /* HAVE_IPV6 */ 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_bgp_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_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); #endif /* HAVE_IPV6 */ install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp neighbors" commands. */ install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); install_element (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 (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); /* Old commands. */ install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp rsclient" commands. */ 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 (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_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 (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_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_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_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); install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp paths" commands. */ install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); /* "show ip bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd); /* "show ip bgp attribute-info" commands. */ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd); /* "redistribute" commands. */ install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd); install_element (BGP_NODE, &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); #ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd); #endif /* HAVE_IPV6 */ /* 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); install_element (ENABLE_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); install_element (ENABLE_NODE, &show_bgp_views_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; } 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++; } 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); install_element (ENABLE_NODE, &show_ip_community_list_cmd); install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd); /* Extcommunity-list. */ install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd); install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd); } quagga-0.99.22.4/bgpd/bgp_vty.h0000644000175000017500000000175312132522417012771 00000000000000/* 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); #endif /* _QUAGGA_BGP_VTY_H */ quagga-0.99.22.4/bgpd/bgp_zebra.c0000644000175000017500000006610212177450262013253 00000000000000/* zebra client Copyright (C) 1997, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "stream.h" #include "network.h" #include "prefix.h" #include "log.h" #include "sockunion.h" #include "zclient.h" #include "routemap.h" #include "thread.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_mpath.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; /* Router-id update message from zebra. */ static int bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length) { struct prefix router_id; struct listnode *node, *nnode; struct bgp *bgp; 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; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { if (!bgp->router_id_static.s_addr) bgp_router_id_set (bgp, &router_id.u.prefix4); } return 0; } /* Inteface addition message from zebra. */ static int bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); 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) { struct stream *s; struct interface *ifp; s = zclient->ibuf; ifp = zebra_interface_state_read (s); 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) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s); 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) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s); 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 (Currently IPv4 only) */ { struct listnode *mnode; struct bgp *bgp; struct peer *peer; struct interface *peer_if; 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->ttl != 1) continue; if (peer->su.sa.sa_family == AF_INET) peer_if = if_lookup_by_ipv4 (&peer->su.sin.sin_addr); else continue; if (ifp == peer_if) BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } static int bgp_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; ifc = zebra_interface_address_read (command, zclient->ibuf); 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) { struct connected *ifc; ifc = zebra_interface_address_read (command, zclient->ibuf); 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) { struct stream *s; struct zapi_ipv4 api; struct in_addr nexthop; struct prefix_ipv4 p; 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; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop.s_addr = stream_get_ipv4 (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); 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 (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", 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); } bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, api.metric, api.type); } 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", 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); } bgp_redistribute_delete((struct prefix *)&p, api.type); } return 0; } #ifdef HAVE_IPV6 /* Zebra route add and delete treatment. */ static int zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; struct in6_addr nexthop; struct prefix_ipv6 p; 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; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, 16); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); 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; /* 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", 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); } bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, api.metric, api.type); } 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", 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); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } return 0; } #endif /* HAVE_IPV6 */ 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; } #ifdef HAVE_IPV6 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; } #endif /* HAVE_IPV6 */ int bgp_nexthop_set (union sockunion *local, union sockunion *remote, struct bgp_nexthop *nexthop, struct peer *peer) { int ret = 0; struct interface *ifp = NULL; memset (nexthop, 0, sizeof (struct bgp_nexthop)); if (!local) return -1; if (!remote) return -1; if (local->sa.sa_family == AF_INET) { nexthop->v4 = local->sin.sin_addr; ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); } #ifdef HAVE_IPV6 if (local->sa.sa_family == AF_INET6) { if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) { if (peer->ifname) ifp = if_lookup_by_index (if_nametoindex (peer->ifname)); } else ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); } #endif /* HAVE_IPV6 */ if (!ifp) return -1; nexthop->ifp = ifp; /* IPv4 connection. */ if (local->sa.sa_family == AF_INET) { #ifdef HAVE_IPV6 /* IPv6 nexthop*/ ret = if_get_ipv6_global (ifp, &nexthop->v6_global); /* There is no global nexthop. */ if (!ret) if_get_ipv6_local (ifp, &nexthop->v6_global); else if_get_ipv6_local (ifp, &nexthop->v6_local); #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 /* IPv6 connection. */ if (local->sa.sa_family == AF_INET6) { struct interface *direct = NULL; /* IPv4 nexthop. I don't care about it. */ if (peer->local_id.s_addr) nexthop->v4 = peer->local_id; /* Global address*/ if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) { memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, IPV6_MAX_BYTELEN); /* If directory connected set link-local address. */ direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr); if (direct) if_get_ipv6_local (ifp, &nexthop->v6_local); } else /* Link-local address. */ { ret = if_get_ipv6_global (ifp, &nexthop->v6_global); /* If there is no global address. Set link-local address as global. I know this break RFC specification... */ if (!ret) memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, IPV6_MAX_BYTELEN); else memcpy (&nexthop->v6_local, &local->sin6.sin6_addr, IPV6_MAX_BYTELEN); } } if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) || if_lookup_by_ipv6 (&remote->sin6.sin6_addr)) peer->shared_network = 1; else peer->shared_network = 0; /* KAME stack specific treatment. */ #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global) && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global)) { SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0); } if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local) && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local)) { SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0); } #endif /* KAME */ #endif /* HAVE_IPV6 */ return ret; } 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; if (zclient->sock < 0) return; if (! zclient->redist[ZEBRA_ROUTE_BGP]) return; flags = 0; peer = info->peer; 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 != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); /* resize nexthop buffer size if necessary */ if ((oldsize = stream_get_size (bgp_nexthop_buf)) < (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1))) { newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)); newsize = stream_resize (bgp_nexthop_buf, newsize); if (newsize == oldsize) { zlog_err ("can't resize nexthop buffer"); return; } } stream_reset (bgp_nexthop_buf); if (p->family == AF_INET) { struct zapi_ipv4 api; struct in_addr *nexthop; 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 = 1 + bgp_info_mpath_count (info); 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; 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" " 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.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); } #ifdef HAVE_IPV6 /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { unsigned int ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; ifindex = 0; nexthop = NULL; 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 (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) { if (info->peer->ifname) ifindex = if_nametoindex (info->peer->ifname); else if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } /* Make Zebra API structure. */ api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %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); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, (struct prefix_ipv6 *) p, &api); } #endif /* HAVE_IPV6 */ } 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 (! zclient->redist[ZEBRA_ROUTE_BGP]) 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 != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); if (p->family == AF_INET) { struct zapi_ipv4 api; struct in_addr *nexthop; api.flags = flags; nexthop = &info->attr->nexthop; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])), api.metric); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); } #ifdef HAVE_IPV6 /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { struct zapi_ipv6 api; unsigned int ifindex; struct in6_addr *nexthop; assert (info->attr->extra); ifindex = 0; nexthop = NULL; /* 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) { nexthop = &info->attr->extra->mp_nexthop_local; if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } if (nexthop == NULL) return; if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) if (info->peer->ifname) ifindex = if_nametoindex (info->peer->ifname); api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %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); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, (struct prefix_ipv6 *) p, &api); } #endif /* HAVE_IPV6 */ } /* Other routes redistribution into BGP. */ int bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) { /* Set flag to BGP instance. */ bgp->redist[afi][type] = 1; /* Return if already redistribute flag is set. */ if (zclient->redist[type]) return CMD_WARNING; zclient->redist[type] = 1; /* Return if zebra connection is not established. */ if (zclient->sock < 0) return CMD_WARNING; 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); 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 (! zclient->redist[type]) return CMD_WARNING; zclient->redist[type] = 0; if (bgp->redist[AFI_IP][type] == 0 && bgp->redist[AFI_IP6][type] == 0 && zclient->sock >= 0) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra send: redistribute delete %s", zebra_route_string(type)); zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); } /* Withdraw redistributed routes from current BGP's routing table. */ bgp_redistribute_withdraw (bgp, afi, type); return CMD_SUCCESS; } /* Unset redistribution route-map configuration. */ int bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type) { if (! bgp->rmap[afi][type].name) return 0; /* Unset route-map. */ free (bgp->rmap[afi][type].name); bgp->rmap[afi][type].name = NULL; bgp->rmap[afi][type].map = NULL; return 1; } /* Unset redistribution metric configuration. */ int bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) { if (! bgp->redist_metric_flag[afi][type]) return 0; /* Unset metric. */ bgp->redist_metric_flag[afi][type] = 0; bgp->redist_metric[afi][type] = 0; return 1; } void bgp_zclient_reset (void) { zclient_reset (zclient); } void bgp_zebra_init (void) { /* Set default values. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_BGP); 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; #ifdef HAVE_IPV6 zclient->ipv6_route_add = zebra_read_ipv6; zclient->ipv6_route_delete = zebra_read_ipv6; #endif /* HAVE_IPV6 */ /* Interface related init. */ if_init (); bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } quagga-0.99.22.4/bgpd/bgp_zebra.h0000644000175000017500000000416212177450262013256 00000000000000/* 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 *)) extern struct stream *bgp_nexthop_buf; extern void bgp_zebra_init (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 int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int); extern int bgp_redistribute_metric_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 *); #ifdef HAVE_IPV6 extern struct interface *if_lookup_by_ipv6 (struct in6_addr *); extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); #endif /* HAVE_IPV6 */ #endif /* _QUAGGA_BGP_ZEBRA_H */ quagga-0.99.22.4/bgpd/bgpd.c0000644000175000017500000043501012177450262012232 00000000000000/* BGP-4, BGP-4+ daemon program Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "thread.h" #include "buffer.h" #include "stream.h" #include "command.h" #include "sockunion.h" #include "network.h" #include "memory.h" #include "filter.h" #include "routemap.h" #include "str.h" #include "log.h" #include "plist.h" #include "linklist.h" #include "workqueue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_filter.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.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. */ 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } /* BGP's cluster-id control. */ int bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) { struct peer *peer; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } int bgp_cluster_id_unset (struct bgp *bgp) { struct peer *peer; struct listnode *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 (peer->status == Established) { 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } else { /* Not doign confederation before, so reset every non-local session */ if (peer_sort (peer) != BGP_PEER_IBGP) { /* Reset the local_as to be our EBGP one */ if (peer_sort (peer) == BGP_PEER_EBGP) peer->local_as = as; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } int bgp_confederation_id_unset (struct bgp *bgp) { struct peer *peer; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } return 0; } /* Is an AS part of the confed or not? */ int bgp_confederation_peers_check (struct bgp *bgp, as_t as) { int i; if (! bgp) return 0; for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i] == as) return 1; return 0; } /* Add an AS to the confederation set. */ int bgp_confederation_peers_add (struct bgp *bgp, as_t as) { struct peer *peer; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } /* Delete an AS from the confederation set. */ int bgp_confederation_peers_remove (struct bgp *bgp, as_t as) { int i; int j; struct peer *peer; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } /* Local preference configuration. */ int bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref) { if (! bgp) return -1; bgp->default_local_pref = local_pref; return 0; } int bgp_default_local_preference_unset (struct bgp *bgp) { if (! bgp) return -1; bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; return 0; } /* 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 (orf_name); /* Set default neighbor send-community. */ if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); } /* Clear neighbor default_originate_rmap */ if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; /* Clear neighbor maximum-prefix */ peer->pmax[afi][safi] = 0; peer->pmax_threshold[afi][safi] = MAXIMUM_PREFIX_THRESHOLD_DEFAULT; } /* peer global config reset */ static void peer_global_config_reset (struct peer *peer) { peer->weight = 0; peer->change_local_as = 0; peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); 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); bgp_unlock(peer->bgp); /* 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); /* Free allocated host character. */ if (peer->host) XFREE (MTYPE_BGP_PEER_HOST, peer->host); /* Update source configuration. */ if (peer->update_source) sockunion_free (peer->update_source); if (peer->update_if) XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); if (peer->clear_node_queue) work_queue_free (peer->clear_node_queue); bgp_sync_delete (peer); memset (peer, 0, sizeof (struct peer)); XFREE (MTYPE_BGP_PEER, peer); } /* increase reference count on a struct peer */ struct peer * peer_lock (struct peer *peer) { assert (peer && (peer->lock >= 0)); 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 (struct peer *peer) { assert (peer && (peer->lock > 0)); peer->lock--; if (peer->lock == 0) { #if 0 zlog_debug ("unlocked and freeing"); zlog_backtrace (LOG_DEBUG); #endif peer_free (peer); return NULL; } #if 0 if (peer->lock == 1) { zlog_debug ("unlocked to 1"); zlog_backtrace (LOG_DEBUG); } #endif 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->v_asorig = BGP_DEFAULT_ASORIGINATE; 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); } peer->orf_plist[afi][safi] = NULL; } SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); /* Create buffers. */ peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer->obuf = stream_fifo_new (); peer->work = stream_new (BGP_MAX_PACKET_SIZE); bgp_sync_init (peer); /* Get service port number. */ sp = getservbyname ("bgp", "tcp"); peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); return peer; } /* Create new BGP peer. */ 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 (); /* Default TTL set. */ peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1; /* 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) { bgp_peer_sort_t type; /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->status == Established) { peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } type = peer_sort (peer); peer->as = as; if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION) && ! bgp_confederation_peers_check (peer->bgp, as) && peer->bgp->as != as) peer->local_as = peer->bgp->confed_id; else peer->local_as = peer->bgp->as; /* Advertisement-interval reset */ if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* TTL reset */ if (peer_sort (peer) == BGP_PEER_IBGP) peer->ttl = 255; else if (type == BGP_PEER_IBGP) peer->ttl = 1; /* reflector-client reset */ if (peer_sort (peer) != BGP_PEER_IBGP) { UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); } /* local-as reset */ if (peer_sort (peer) != BGP_PEER_EBGP) { peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); 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 = peer_create (su, bgp, local_as, *as, 0, 0); else peer = peer_create (su, bgp, local_as, *as, afi, safi); } return 0; } /* Activate the peer or peer group for specified AFI and SAFI. */ int peer_activate (struct peer *peer, afi_t afi, safi_t safi) { int active; if (peer->afc[afi][safi]) return 0; /* Activate the address family configuration. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) peer->afc[afi][safi] = 1; else { active = peer_active (peer); peer->afc[afi][safi] = 1; if (! 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; } 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); /* 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); if (peer->obuf) stream_fifo_free (peer->obuf); if (peer->work) stream_free (peer->work); peer->obuf = NULL; peer->work = peer->ibuf = NULL; /* Local and remote addresses. */ if (peer->su_local) sockunion_free (peer->su_local); if (peer->su_remote) sockunion_free (peer->su_remote); peer->su_local = 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); if (filter->plist[i].name) free (filter->plist[i].name); if (filter->aslist[i].name) free (filter->aslist[i].name); filter->dlist[i].name = NULL; filter->plist[i].name = NULL; 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); if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); filter->usmap.name = NULL; peer->default_rmap[afi][safi].name = NULL; } 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_IP6][SAFI_UNICAST] || peer->af_group[AFI_IP6][SAFI_MULTICAST]) 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 = 1; 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 (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_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->group = NULL; 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->group = NULL; peer_delete (peer); } list_delete_all_node (group->peer); group->conf->as = 0; return 0; } /* Bind specified peer to peer group. */ int peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer_group *group, afi_t afi, safi_t safi, as_t *as) { struct peer *peer; int first_member = 0; /* 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 (peer_sort (group->conf) == BGP_PEER_IBGP) group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* ebgp-multihop reset */ if (peer_sort (group->conf) == BGP_PEER_IBGP) group->conf->ttl = 255; /* local-as reset */ if (peer_sort (group->conf) != BGP_PEER_EBGP) { group->conf->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); 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 (peer->status == Established) { 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_RMAP_UNBIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* BGP instance creation by `router bgp' commands. */ 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->as = *as; if (name) bgp->name = strdup (name); return bgp; } /* Return first entry of BGP. */ struct bgp * bgp_get_default (void) { if (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; struct listnode *next; afi_t afi; int i; /* Delete static route. */ bgp_static_delete (bgp); /* Unset redistribution. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != ZEBRA_ROUTE_BGP) bgp_redistribute_unset (bgp, afi, i); for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) peer_delete (peer); for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) peer_group_delete (group); assert (listcount (bgp->rsclient) == 0); if (bgp->peer_self) { peer_delete(bgp->peer_self); bgp->peer_self = NULL; } /* 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_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST]) return 1; return 0; } /* If peer is negotiated at least one address family return 1. */ int peer_active_nego (struct peer *peer) { if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MULTICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) return 1; return 0; } /* peer_flag_change_type. */ enum peer_change_type { peer_change_none, peer_change_reset, peer_change_reset_in, peer_change_reset_out, }; 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 (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_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 }, { 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 (peer->status == Established) 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 (peer->status == Established) { 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 0; /* see comment in peer_ttl_security_hops_set() */ if (ttl != MAXTTL) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; if (group->conf->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->sort == BGP_PEER_IBGP) continue; if (peer1->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } else { if (peer->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } peer->ttl = ttl; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = group->conf->ttl; if (peer->fd >= 0) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } } return 0; } int peer_ebgp_multihop_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; if (peer->sort == BGP_PEER_IBGP) return 0; if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; if (peer_group_active (peer)) peer->ttl = peer->group->conf->ttl; else peer->ttl = 1; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = 1; if (peer->fd >= 0) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } } return 0; } /* Neighbor description. */ int peer_description_set (struct peer *peer, char *desc) { if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc); return 0; } int peer_description_unset (struct peer *peer) { if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); peer->desc = NULL; return 0; } /* Neighbor update-source. */ int peer_update_source_if_set (struct peer *peer, 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* peer-group member updates. */ group = peer->group; 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_update_source_addr_set (struct peer *peer, union sockunion *su) { struct peer_group *group; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* peer-group member updates. */ group = peer->group; 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_update_source_unset (struct peer *peer) { union sockunion *su; struct peer_group *group; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* peer-group member updates. */ group = peer->group; 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi, 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) { 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; return 0; } int peer_timers_connect_unset (struct peer *peer) { 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; return 0; } int peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) { 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; return 0; } int peer_advertise_interval_unset (struct peer *peer) { 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; 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } group = peer->group; 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_local_as_unset (struct peer *peer) { struct peer_group *group; struct listnode *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 (peer->status == Established) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } group = peer->group; 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 (peer->status == Established) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } /* 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 (peer->status == Established) 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 (peer->status == Established) 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 (peer->status == Established) 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 (peer->status == Established) 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 (struct access_list *access) { 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)) return 0; 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); } 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; int ret; zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); if (peer->sort == BGP_PEER_IBGP) return BGP_ERR_NO_IBGP_WITH_TTLHACK; /* We cannot configure ttl-security hops when ebgp-multihop is already set. For non peer-groups, the check is simple. For peer-groups, it's slightly messy, because we need to check both the peer-group structure and all peer-group members for any trace of ebgp-multihop configuration before actually applying the ttl-security rules. Cisco really made a mess of this configuration parameter, and OpenBGPD got it right. */ if (peer->gtsm_hops == 0) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; if (group->conf->ttl != 1) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->sort == BGP_PEER_IBGP) continue; if (peer1->ttl != 1) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } else { if (peer->ttl != 1) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } /* specify MAXTTL on outgoing packets */ ret = peer_ebgp_multihop_set (peer, MAXTTL); if (ret != 0) return ret; } peer->gtsm_hops = gtsm_hops; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; peer->gtsm_hops = group->conf->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) { if (peer->fd >= 0 && peer->gtsm_hops != 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); } 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_ttl_security_hops_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; struct peer *opeer; zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); if (peer->sort == BGP_PEER_IBGP) return 0; /* if a peer-group member, then reset to peer-group default rather than 0 */ if (peer_group_active (peer)) peer->gtsm_hops = peer->group->conf->gtsm_hops; else peer->gtsm_hops = 0; opeer = peer; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; peer->gtsm_hops = 0; if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } } return peer_ebgp_multihop_unset (opeer); } 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 (peer->status == Established) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_RESET); else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, enum bgp_clear_type stype) { if (peer->status != Established) return 0; if (! peer->afc[afi][safi]) return BGP_ERR_AF_UNCONFIGURED; if (stype == BGP_CLEAR_SOFT_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 60*60*24*7 if (uptime1 < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime1 < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } 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); /* EBGP multihop. */ if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 && !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) if (! peer_group_active (peer) || g_peer->ttl != peer->ttl) vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, VTY_NEWLINE); /* ttl-security hops */ if (peer->sort != BGP_PEER_IBGP && peer->gtsm_hops != 0) if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, peer->gtsm_hops, 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)) 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)) 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", addr, 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)) vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE); else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " neighbor %s send-community extended%s", addr, VTY_NEWLINE); else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE); } else { if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " no neighbor %s send-community both%s", addr, VTY_NEWLINE); else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " no neighbor %s send-community extended%s", addr, VTY_NEWLINE); else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) vty_out (vty, " no neighbor %s send-community%s", addr, VTY_NEWLINE); } } /* Default information */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE) && ! peer->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 unicast"); } else if (afi == AFI_IP6) { 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); 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, " 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_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_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 scan interval. */ bgp_config_write_scan_time (vty); /* 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); /* 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); /* 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); 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) { /* BGP VTY commands installation. */ bgp_vty_init (); /* Init zebra. */ bgp_zebra_init (); /* BGP inits. */ bgp_attr_init (); bgp_debug_init (); bgp_dump_init (); bgp_route_init (); bgp_route_map_init (); bgp_address_init (); bgp_scan_init (); bgp_mplsvpn_init (); /* Access list initialize. */ access_list_init (); access_list_add_hook (peer_distribute_update); access_list_delete_hook (peer_distribute_update); /* Filter list initialize. */ bgp_filter_init (); as_list_add_hook (peer_aslist_update); as_list_delete_hook (peer_aslist_update); /* Prefix list initialize.*/ prefix_list_init (); prefix_list_add_hook (peer_prefix_list_update); prefix_list_delete_hook (peer_prefix_list_update); /* Community list initialize. */ bgp_clist = community_list_init (); #ifdef HAVE_SNMP bgp_snmp_init (); #endif /* HAVE_SNMP */ } 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-0.99.22.4/bgpd/bgpd.conf.sample0000644000175000017500000000106612000052240014170 00000000000000! -*- 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-0.99.22.4/bgpd/bgpd.conf.sample20000644000175000017500000000536112000052240014254 00000000000000! ! 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-0.99.22.4/bgpd/bgpd.h0000644000175000017500000010455012177450262012241 00000000000000/* 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; /* BGP flags. */ u_int16_t flags; #define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0) #define BGP_FLAG_DETERMINISTIC_MED (1 << 1) #define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2) #define BGP_FLAG_MED_CONFED (1 << 3) #define BGP_FLAG_NO_DEFAULT_IPV4 (1 << 4) #define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 5) #define BGP_FLAG_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) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) /* Static route configuration. */ struct bgp_table *route[AFI_MAX][SAFI_MAX]; /* Aggregate address configuration. */ struct bgp_table *aggregate[AFI_MAX][SAFI_MAX]; /* BGP routing information base. */ struct bgp_table *rib[AFI_MAX][SAFI_MAX]; /* BGP redistribute configuration. */ u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX]; /* BGP redistribute metric configuration. */ u_char redist_metric_flag[AFI_MAX][ZEBRA_ROUTE_MAX]; u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX]; /* BGP redistribute route-map. */ struct { char *name; struct route_map *map; } rmap[AFI_MAX][ZEBRA_ROUTE_MAX]; /* BGP distance configuration. */ u_char distance_ebgp; u_char distance_ibgp; u_char distance_local; /* BGP default local-preference. */ u_int32_t default_local_pref; /* BGP default timer. */ u_int32_t default_holdtime; u_int32_t default_keepalive; /* BGP graceful restart */ u_int32_t restart_time; u_int32_t stalepath_time; /* 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; #ifdef HAVE_IPV6 struct in6_addr v6_global; struct in6_addr v6_local; #endif /* HAVE_IPV6 */ }; /* BGP router distinguisher value. */ #define BGP_RD_SIZE 8 struct bgp_rd { u_char val[BGP_RD_SIZE]; }; #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; /* 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; /* 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 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 */ unsigned int ifindex; /* ifindex of the BGP connection. */ char *ifname; /* bind interface name. */ char *update_if; union sockunion *update_source; struct zlog *log; union sockunion *su_local; /* Sockunion of local address. */ union sockunion *su_remote; /* Sockunion of remote address. */ int shared_network; /* Is this peer shared same network. */ struct bgp_nexthop nexthop; /* Nexthop */ /* Peer address family configuration. */ u_char afc[AFI_MAX][SAFI_MAX]; u_char afc_nego[AFI_MAX][SAFI_MAX]; u_char afc_adv[AFI_MAX][SAFI_MAX]; u_char afc_recv[AFI_MAX][SAFI_MAX]; /* Capability flags (reset in bgp_stop) */ u_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 */ /* 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 */ /* 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_HAVE_ACCEPT (1 << 3) /* accept peer's parent */ #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_asorig; 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_asorig; 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 /* 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_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_EVENTS_MAX 15 /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 #define BGP_ERROR_START_TIMER 30 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 #define BGP_DEFAULT_ASORIGINATE 15 #define BGP_DEFAULT_EBGP_ROUTEADV 30 #define BGP_DEFAULT_IBGP_ROUTEADV 5 #define BGP_CLEAR_CONNECT_RETRY 20 #define BGP_DEFAULT_CONNECT_RETRY 120 /* BGP default local preference. */ #define BGP_DEFAULT_LOCAL_PREF 100 /* BGP graceful restart */ #define BGP_DEFAULT_RESTART_TIME 120 #define BGP_DEFAULT_STALEPATH_TIME 360 /* 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))) /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) /* BGP error codes. */ #define BGP_SUCCESS 0 #define BGP_ERR_INVALID_VALUE -1 #define BGP_ERR_INVALID_FLAG -2 #define BGP_ERR_INVALID_AS -3 #define BGP_ERR_INVALID_BGP -4 #define BGP_ERR_PEER_GROUP_MEMBER -5 #define BGP_ERR_MULTIPLE_INSTANCE_USED -6 #define BGP_ERR_PEER_GROUP_MEMBER_EXISTS -7 #define BGP_ERR_PEER_BELONGS_TO_GROUP -8 #define BGP_ERR_PEER_GROUP_AF_UNCONFIGURED -9 #define BGP_ERR_PEER_GROUP_NO_REMOTE_AS -10 #define BGP_ERR_PEER_GROUP_CANT_CHANGE -11 #define BGP_ERR_PEER_GROUP_MISMATCH -12 #define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT -13 #define BGP_ERR_MULTIPLE_INSTANCE_NOT_SET -14 #define BGP_ERR_AS_MISMATCH -15 #define BGP_ERR_PEER_INACTIVE -16 #define BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER -17 #define BGP_ERR_PEER_GROUP_HAS_THE_FLAG -18 #define BGP_ERR_PEER_FLAG_CONFLICT -19 #define BGP_ERR_PEER_GROUP_SHUTDOWN -20 #define BGP_ERR_PEER_FILTER_CONFLICT -21 #define BGP_ERR_NOT_INTERNAL_PEER -22 #define BGP_ERR_REMOVE_PRIVATE_AS -23 #define BGP_ERR_AF_UNCONFIGURED -24 #define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED -25 #define BGP_ERR_INSTANCE_MISMATCH -26 #define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP -27 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -28 #define BGP_ERR_TCPSIG_FAILED -29 #define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30 #define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 #define BGP_ERR_MAX -32 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -33 extern struct bgp_master *bm; extern struct thread_master *master; /* 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 *); extern struct peer *peer_lock (struct peer *); extern struct peer *peer_unlock (struct peer *); 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 int bgp_router_id_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, u_int32_t); 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_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_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_ebgp_multihop_unset (struct peer *); extern int peer_description_set (struct peer *, 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 *, 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, u_int32_t); 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 int peer_ttl_security_hops_unset (struct peer *); #endif /* _QUAGGA_BGPD_H */ quagga-0.99.22.4/compile0000755000175000017500000001624512070614057011615 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2012 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-0.99.22.4/config.guess0000755000175000017500000013014512156517720012557 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-05-16' # 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. # # 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;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. 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-2013 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'` ;; 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=`(/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 ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in 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 # 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/[-_].*/\./'` ;; 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}" 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 ;; *: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 ;; 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/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` 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 ;; i*: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 '[A-Z]' '[a-z]'``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 ;; 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 ;; 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; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32: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 ;; 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}-unknown-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 configury 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 ;; 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 [ "$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 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 ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: quagga-0.99.22.4/config.h.in0000644000175000017500000005114612211704501012250 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* babeld vty socket */ #undef BABEL_VTYSH_PATH /* bgpd vty socket */ #undef BGP_VTYSH_PATH /* BSDI */ #undef BSDI_NRL /* Mask for config files */ #undef CONFIGFILE_MASK /* Consumed Time Check */ #undef CONSUMED_TIME_CHECK /* daemon vty directory */ #undef DAEMON_VTY_DIR /* 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 Alias */ #undef HAVE_BROKEN_ALIASES /* 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 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 `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 /* __inet_aton */ #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 /* Linux IPv6 */ #undef HAVE_IPV6 /* 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 /* Define to 1 if you have the `kvm' library (-lkvm). */ #undef HAVE_LIBKVM /* 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_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 /* 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 /* OSPF Opaque LSA */ #undef HAVE_OPAQUE_LSA /* Have openpam.h */ #undef HAVE_OPENPAM_H /* OSPF TE */ #undef HAVE_OSPF_TE /* 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 /* /proc/net/dev */ #undef HAVE_PROC_NET_DEV /* /proc/net/if_inet6 */ #undef HAVE_PROC_NET_IF_INET6 /* 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 /* Have setproctitle */ #undef HAVE_SETPROCTITLE /* 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 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 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 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 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 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_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 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 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 /* INRIA IPv6 */ #undef INRIA_IPV6 /* IRIX 6.5 */ #undef IRIX_65 /* 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 stack */ #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 in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Musica IPv6 stack */ #undef MUSICA /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* NRL */ #undef NRL /* 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 /* babeld PID */ #undef PATH_BABELD_PID /* bgpd PID */ #undef PATH_BGPD_PID /* isisd PID */ #undef PATH_ISISD_PID /* ospf6d PID */ #undef PATH_OSPF6D_PID /* ospfd PID */ #undef PATH_OSPFD_PID /* ripd PID */ #undef PATH_RIPD_PID /* ripngd PID */ #undef PATH_RIPNGD_PID /* watchquagga PID */ #undef PATH_WATCHQUAGGA_PID /* zebra PID */ #undef PATH_ZEBRA_PID /* Quagga Group */ #undef QUAGGA_GROUP /* Hide deprecated interfaces */ #undef QUAGGA_NO_DEPRECATED_INTERFACES /* Quagga User */ #undef QUAGGA_USER /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* 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-0.99.22.4/config.sub0000755000175000017500000010565712156517720012234 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-04-24' # 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 with a ChangeLog entry to config-patches@gnu.org. # # 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;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -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-2013 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* | \ kopensolaris*-gnu* | \ 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 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx | dvp \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | 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 \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | 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 \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | 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 ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | 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-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | 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-* \ | 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-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | 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-* \ | 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 ;; 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 ;; 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 ;; 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=i386-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 ;; mipsEE* | ee | ps2) basic_machine=mips64r5900el-scei case $os in -linux*) ;; *) os=-elf ;; esac ;; iop) basic_machine=mipsel-scei os=-irx ;; dvp) basic_machine=dvp-scei os=-elf ;; 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 ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-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 | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) 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* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -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* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -irx* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # 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*) ;; -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 ;; 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 ;; or1k-*) 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-0.99.22.4/configure0000755000175000017500000236513012211704500012136 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Quagga 0.99.22.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='0.99.22.4' PACKAGE_STRING='Quagga 0.99.22.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 PILDFLAGS PICFLAGS CONFDATE WEAK_ALIAS_CROSSFILE WEAK_ALIAS LIBCAP NETSNMP_CONFIG LIB_REGEX HAVE_LIBPCREPOSIX OSPFAPI OSPFCLIENT CURSES INCLUDES VTYSH SOLARIS ISISD WATCHQUAGGA BABELD OSPF6D OSPFD RIPNGD RIPD BGPD ZEBRA BUILD_TESTS DOC ISISD_FALSE ISISD_TRUE OSPF6D_FALSE OSPF6D_TRUE RIPNGD_FALSE RIPNGD_TRUE OSPFCLIENT_FALSE OSPFCLIENT_TRUE WATCHQUAGGA_FALSE WATCHQUAGGA_TRUE BABELD_FALSE BABELD_TRUE OSPFD_FALSE OSPFD_TRUE RIPD_FALSE RIPD_TRUE BGPD_FALSE BGPD_TRUE ZEBRA_FALSE ZEBRA_TRUE LIB_IPV6 IPFORWARD IF_PROC IOCTL_METHOD IF_METHOD RTREAD_METHOD HAVE_NETLINK_FALSE HAVE_NETLINK_TRUE OTHER_METHOD KERNEL_METHOD RT_METHOD LIBM LIBOBJS LIBPAM VTYSH_FALSE VTYSH_TRUE LIBREADLINE GIT_VERSION_FALSE GIT_VERSION_TRUE MULTIPATH_NUM enable_vty_group enable_group enable_user ISIS_TOPOLOGY_LIB ISIS_TOPOLOGY_DIR ISIS_TOPOLOGY_INCLUDES OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR DLLTOOL OBJDUMP NM ac_ct_DUMPBIN DUMPBIN LD FGREP LIBTOOL AR LN_S HAVE_LATEX_FALSE HAVE_LATEX_TRUE LATEXMK PDFLATEX SED 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__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 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_exampledir enable_pkgsrcrcdir with_cflags enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock with_pkg_extra_version with_pkg_git_version enable_vtysh enable_ipv6 enable_doc enable_tests enable_zebra enable_bgpd enable_ripd enable_ripngd enable_ospfd enable_ospf6d enable_babeld enable_watchquagga enable_isisd enable_solaris enable_bgp_announce enable_netlink enable_broken_aliases enable_snmp with_libpam enable_tcp_zebra enable_opaque_lsa enable_ospfapi enable_ospfclient enable_ospf_te 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_time_check enable_pcreposix enable_fpm enable_largefile enable_pie ' ac_precious_vars='build_alias host_alias target_alias GAWK CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # 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 0.99.22.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 0.99.22.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-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) --enable-vtysh include integrated vty shell for Quagga --disable-ipv6 turn off IPv6 related features and daemons --disable-doc do not build docs --disable-tests do not build tests --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-babeld do not build babeld --disable-watchquagga do not build watchquagga --enable-isisd build isisd --enable-solaris build solaris --disable-bgp-announce, turn off BGP route announcement --enable-netlink force to use Linux netlink interface --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X --enable-snmp=ARG enable SNMP support (smux or agentx) --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon --disable-opaque-lsa do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370) --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) --disable-ospf-te disable Traffic Engineering Extension to OSPF --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 gcc linking with -rdynamic for better backtraces --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 --disable-largefile omit support for large files --disable-pie Do not build tools as a Position Independent Executables 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-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 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 0.99.22.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 0.99.22.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 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}- am__api_version='1.12' # 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 --run true"; then am_missing_run="$MISSING --run " 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}" != 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 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='0.99.22.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. 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}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' 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 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 if test "x$CC" != xcc; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 $as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } else { $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; } fi set dummy $CC; ac_cc=`$as_echo "$2" | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` if eval \${ac_cv_prog_cc_${ac_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. # We do the test twice because some compilers refuse to overwrite an # existing .o file with -o, though they will create one. ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { 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; } && test -f conftest2.$ac_objext && { { 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 eval ac_cv_prog_cc_${ac_cc}_c_o=yes if test "x$CC" != xcc; then # Test first that cc exists at all. if { ac_try='cc -c conftest.$ac_ext >&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_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { 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; } && test -f conftest2.$ac_objext && { { 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 # cc works too. : else # cc exists but doesn't like -o. eval ac_cv_prog_cc_${ac_cc}_c_o=no fi fi fi else eval ac_cv_prog_cc_${ac_cc}_c_o=no fi rm -f core conftest* fi if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; 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_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h fi # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != 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 { $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" # 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 if test "x${GCC}" = "xyes" ; then COMPILER="GCC" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the Intel compiler" >&5 $as_echo_n "checking whether we are using the Intel compiler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ __INTEL_COMPILER _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "^__INTEL_COMPILER" >/dev/null 2>&1; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else COMPILER="ICC" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f conftest* else { $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 : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else COMPILER="SUNPRO" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to set a default CFLAGS" >&5 $as_echo_n "checking whether to set a default CFLAGS... " >&6; } if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in "ICC") CFLAGS="-Os -g -Wall" { $as_echo "$as_me:${as_lineno-$LINENO}: result: Intel default" >&5 $as_echo "Intel default" >&6; } ;; "GCC") CFLAGS="-Os -fno-omit-frame-pointer -g -std=gnu99 -Wall" CFLAGS="${CFLAGS} -Wsign-compare -Wpointer-arith" CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" CFLAGS="${CFLAGS} -Wmissing-prototypes -Wmissing-declarations" CFLAGS="${CFLAGS} -Wchar-subscripts -Wcast-qual" # TODO: conditionally addd -Wpacked if handled { $as_echo "$as_me:${as_lineno-$LINENO}: result: gcc default" >&5 $as_echo "gcc default" >&6; } ;; "SUNPRO") CFLAGS="-xO4 -v -g -xspace -xcode=pic32 -xstrconst -xc99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: SunPro default" >&5 $as_echo "SunPro default" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown compiler" >&5 $as_echo "unknown compiler" >&6; } ;; esac else { $as_echo "$as_me:${as_lineno-$LINENO}: result: CFLAGS supplied by user" >&5 $as_echo "CFLAGS supplied by user" >&6; } 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; } { $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.2' macro_revision='1.3337' 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 "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; 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 "$with_gnu_ld" = yes; 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 case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) 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 "$lt_cv_path_NM" != "no"; 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 /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) 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; } # 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; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # 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"; 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 $i != 17 # 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"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } 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 "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; 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 # which 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. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && 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 ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; 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) 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*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 ;; 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 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 "$ac_status" -eq 0; 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 "$ac_status" -ne 0; 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 "x$lt_cv_ar_at_file" = xno; 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 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 "$host_cpu" = ia64; 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 # 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 -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$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 -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/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 # and D for any global 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};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print 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 con'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* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$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 "$pipe_works" = yes; 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 "$GCC" = yes; 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; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && 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 which ABI we are using. 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 which ABI we are using. 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 "$lt_cv_prog_gnu_ld" = yes; 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* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. 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*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|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" ;; ppc*-*linux*|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 x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. 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*) 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 "x$lt_cv_path_mainfest_tool" != xyes; 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 $_lt_result -eq 0; 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 $_lt_result -eq 0 && $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 "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; 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 "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; 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 test -z "$pic_mode" && pic_mode=default # 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 # 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 "X${COLLECT_NAMES+set}" != Xset; 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 for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # 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 "$GCC" = yes; 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" # 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 x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; 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 "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; 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' ;; 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 "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; 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' ;; 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) 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' ;; 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 which 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" # 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 x"$lt_cv_prog_compiler_pic_works" = xyes; 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 x"$lt_cv_prog_compiler_static_works" = xyes; 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 "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; 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 "$hard_links" = no; 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 "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) 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 "$with_gnu_ld" = yes; 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 "$lt_use_gnu_ld_interface" = yes; 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 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 "$host_cpu" != ia64; 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 (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; 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 ;; 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 "$host_os" = linux-dietlibc; 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 "$tmp_diet" = no 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' ;; 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 "x$supports_anon_versioning" = xyes; 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 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 "x$supports_anon_versioning" = xyes; 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 can not *** 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 "$ld_shlibs" = no; 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 "$GCC" = yes && 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 "$host_cpu" = ia64; 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 AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". 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) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | 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 # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; 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,' if test "$GCC" = yes; 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 "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; 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 "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi 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_use_runtimelinking" = yes; 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 "${lt_cv_aix_libpath+set}" = 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 "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; 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 "${lt_cv_aix_libpath+set}" = 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 "$with_gnu_ld" = yes; 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 # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' 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~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $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 "$lt_cv_ld_force_load" = "yes"; 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*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; 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 "$GCC" = yes; 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 $output_objdir/$soname = $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 $output_objdir/$soname = $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 "$GCC" = yes && test "$with_gnu_ld" = no; 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 "$with_gnu_ld" = no; 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 "$GCC" = yes && test "$with_gnu_ld" = no; 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 x"$lt_cv_prog_compiler__b" = xyes; 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 "$with_gnu_ld" = no; 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 "$GCC" = yes; 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 "$lt_cv_irix_exported_symbol" = yes; 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 ;; 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*) 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__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; 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 "$GCC" = yes; 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 "$GCC" = yes; 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 "$GCC" = yes; 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 "x$host_vendor" = xsequent; 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 "$GCC" = yes; 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 can NOT 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 "$GCC" = yes; 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 x$host_vendor = xsni; 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 "$ld_shlibs" = no && 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 "$enable_shared" = yes && test "$GCC" = yes; 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 "$GCC" = yes; 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` 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" else 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 "$host_cpu" = ia64; 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 # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # 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}' else # 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' fi 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%'\''`; test $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 # Handle Gentoo/FreeBSD as it was Linux case $host_vendor in gentoo) version_type=linux ;; *) version_type=freebsd-$objformat ;; esac case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; linux) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' need_lib_prefix=no need_version=no ;; 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 ;; 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' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; 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=yes 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 "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; 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 "$lt_cv_prog_gnu_ld" = yes; 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 ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-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 # Append ld.so.conf contents 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="/lib /usr/lib $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*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac 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 if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; 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 "$with_gnu_ld" = yes; 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=freebsd-elf 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 "$with_gnu_ld" = yes; 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 "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $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 "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # 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 "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; 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 "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; 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 ;; *) 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 "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && 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 "$cross_compiling" = yes; 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 -fvisbility=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 "x$lt_cv_dlopen_self" = xyes; 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 "$cross_compiling" = yes; 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 -fvisbility=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 which 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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: # 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-ipv6 was given. if test "${enable_ipv6+set}" = set; then : enableval=$enable_ipv6; fi # Check whether --enable-doc was given. if test "${enable_doc+set}" = set; then : enableval=$enable_doc; fi # Check whether --enable-tests was given. if test "${enable_tests+set}" = set; then : enableval=$enable_tests; 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-babeld was given. if test "${enable_babeld+set}" = set; then : enableval=$enable_babeld; 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-solaris was given. if test "${enable_solaris+set}" = set; then : enableval=$enable_solaris; fi # Check whether --enable-bgp-announce was given. if test "${enable_bgp_announce+set}" = set; then : enableval=$enable_bgp_announce; fi # Check whether --enable-netlink was given. if test "${enable_netlink+set}" = set; then : enableval=$enable_netlink; fi # Check whether --enable-broken-aliases was given. if test "${enable_broken_aliases+set}" = set; then : enableval=$enable_broken_aliases; 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-opaque-lsa was given. if test "${enable_opaque_lsa+set}" = set; then : enableval=$enable_opaque_lsa; 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-ospf-te was given. if test "${enable_ospf_te+set}" = set; then : enableval=$enable_ospf_te; 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-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 if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" CFLAGS="${CFLAGS} -Wpacked -Wpadded" fi if test x"${enable_gcc_rdynamic}" = x"yes" ; then LDFLAGS="${LDFLAGS} -rdynamic" 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 "${enable_broken_aliases}" = "yes"; then if test "${enable_netlink}" = "yes" 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 $? "Sorry you can not use netlink with broken aliases See \`config.log' for more details" "$LINENO" 5; } fi $as_echo "#define HAVE_BROKEN_ALIASES /**/" >>confdefs.h enable_netlink=no fi if test "${enable_tcp_zebra}" = "yes"; then $as_echo "#define HAVE_TCP_ZEBRA /**/" >>confdefs.h fi if test "${enable_opaque_lsa}" != "no"; then $as_echo "#define HAVE_OPAQUE_LSA /**/" >>confdefs.h fi if test "${enable_ospf_te}" != "no"; then $as_echo "#define HAVE_OPAQUE_LSA /**/" >>confdefs.h $as_echo "#define HAVE_OSPF_TE /**/" >>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}" = "yes" && 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 "${enable_user}" = "yes" || test x"${enable_user}" = x""; then enable_user="quagga" elif test "${enable_user}" = "no"; then enable_user="root" fi if test "${enable_group}" = "yes" || test x"${enable_group}" = x""; then enable_group="quagga" elif test "${enable_group}" = "no"; then enable_group="root" 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 cat >>confdefs.h <<_ACEOF #define QUAGGA_USER "${enable_user}" _ACEOF cat >>confdefs.h <<_ACEOF #define QUAGGA_GROUP "${enable_group}" _ACEOF 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 MULTIPATH_NUM=1 case "${enable_multipath}" in [0-9]|[1-9][0-9]) MULTIPATH_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 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 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 return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if ${ac_cv_type_signal+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_type_signal=int else ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF { $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/param.h limits.h signal.h \ sys/socket.h netinet/in.h time.h sys/time.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 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 ;; *-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 ;; *-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 ;; *-linux*) opsys=gnu-linux $as_echo "#define GNU_LINUX /**/" >>confdefs.h ;; *-nec-sysv4*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} 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. */ /* 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 gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=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_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } if ${ac_cv_lib_socket_socket+:} 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. */ /* 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 socket (); int main () { return socket (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_socket=yes else ac_cv_lib_socket_socket=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_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } if test "x$ac_cv_lib_socket_socket" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi ;; *-openbsd*) opsys=openbsd $as_echo "#define OPEN_BSD /**/" >>confdefs.h ;; *-bsdi*) opsys=bsdi OTHER_METHOD="mtu_kvm.o" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkvm" >&5 $as_echo_n "checking for main in -lkvm... " >&6; } if ${ac_cv_lib_kvm_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkvm $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_kvm_main=yes else ac_cv_lib_kvm_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_kvm_main" >&5 $as_echo "$ac_cv_lib_kvm_main" >&6; } if test "x$ac_cv_lib_kvm_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBKVM 1 _ACEOF LIBS="-lkvm $LIBS" fi ;; *-irix6.5) opsys=irix $as_echo "#define IRIX_65 /**/" >>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 "yes") 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="$LIBREADLINE -lreadline" 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 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 for ac_func in setproctitle do : ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" if test "x$ac_cv_func_setproctitle" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETPROCTITLE 1 _ACEOF else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setproctitle in -lutil" >&5 $as_echo_n "checking for setproctitle in -lutil... " >&6; } if ${ac_cv_lib_util_setproctitle+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lutil $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 setproctitle (); int main () { return setproctitle (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_util_setproctitle=yes else ac_cv_lib_util_setproctitle=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_util_setproctitle" >&5 $as_echo "$ac_cv_lib_util_setproctitle" >&6; } if test "x$ac_cv_lib_util_setproctitle" = xyes; then : LIBS="$LIBS -lutil" $as_echo "#define HAVE_SETPROCTITLE /**/" >>confdefs.h fi fi done { $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 if test "${enable_netlink}" = "yes";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 elif test "${enable_netlink}" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: ioctl" >&5 $as_echo "ioctl" >&6; } RT_METHOD=rt_ioctl.o netlink=no else { $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 fi elif test x"$opsys" = x"sol2-6";then { $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" elif test x"$opsys" = x"sol8";then { $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" elif test "$opsys" = "irix" ; then { $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" else if test "$cross_compiling" = yes; then : KERNEL_METHOD=kernel_socket.o RT_METHOD=rt_socket.o { $as_echo "$as_me:${as_lineno-$LINENO}: result: socket" >&5 $as_echo "socket" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include main () { int ac_sock; ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); if (ac_sock < 0 && errno == EINVAL) exit (1); exit (0); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : KERNEL_METHOD=kernel_socket.o RT_METHOD=rt_socket.o { $as_echo "$as_me:${as_lineno-$LINENO}: result: socket" >&5 $as_echo "socket" >&6; } else RT_METHOD=rt_ioctl.o { $as_echo "$as_me:${as_lineno-$LINENO}: result: ioctl" >&5 $as_echo "ioctl" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi 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 /proc/net/route /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 "/proc/net/route") quagga_cv_rtread_method="proc";; "/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" = "irix" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: IRIX" >&5 $as_echo "IRIX" >&6; } IF_METHOD=if_ioctl.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 { $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__) 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 if test "$netlink" != yes; then if test -r /proc/net/dev; then $as_echo "#define HAVE_PROC_NET_DEV /**/" >>confdefs.h IF_PROC=if_proc.o fi if test -r /proc/net/if_inet6; then $as_echo "#define HAVE_PROC_NET_IF_INET6 /**/" >>confdefs.h IF_PROC=if_proc.o 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 *-nec-sysv4*) quagga_cv_ipforward_method="ews";; *-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 test "${enable_ipv6}" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then zebra_cv_ipv6=yes $as_echo "#define HAVE_IPV6 1" >>confdefs.h $as_echo "#define INRIA_IPV6 1" >>confdefs.h RIPNGD="ripngd" OSPF6D="ospf6d" LIB_IPV6="" { $as_echo "$as_me:${as_lineno-$LINENO}: result: INRIA IPv6" >&5 $as_echo "INRIA IPv6" >&6; } elif grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes $as_echo "#define HAVE_IPV6 1" >>confdefs.h $as_echo "#define KAME 1" >>confdefs.h RIPNGD="ripngd" OSPF6D="ospf6d" if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then LIB_IPV6="-L/usr/local/v6/lib -linet6" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: KAME" >&5 $as_echo "KAME" >&6; } elif grep MUSICA /usr/include6/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes $as_echo "#define HAVE_IPV6 1" >>confdefs.h $as_echo "#define MUSICA 1" >>confdefs.h $as_echo "#define KAME 1" >>confdefs.h RIPNGD="ripngd" OSPF6D="ospf6d" if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then LIB_IPV6="-L/usr/local/v6/lib -linet6" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: MUSICA" >&5 $as_echo "MUSICA" >&6; } elif grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes $as_echo "#define HAVE_IPV6 1" >>confdefs.h $as_echo "#define NRL 1" >>confdefs.h RIPNGD="ripngd" OSPF6D="ospf6d" if test x"$opsys" = x"bsdi";then $as_echo "#define BSDI_NRL /**/" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: BSDI_NRL" >&5 $as_echo "BSDI_NRL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: NRL" >&5 $as_echo "NRL" >&6; } fi elif test x"$opsys" = x"sol8"; then zebra_cv_ipv6=yes; $as_echo "#define HAVE_IPV6 1" >>confdefs.h $as_echo "#define SOLARIS_IPV6 1" >>confdefs.h RIPNGD="ripngd" OSPF6D="ospf6d" { $as_echo "$as_me:${as_lineno-$LINENO}: result: Solaris IPv6" >&5 $as_echo "Solaris IPv6" >&6; } elif test "${enable_ipv6}" = "yes"; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* 2.1.128 or later */ #if LINUX_VERSION_CODE >= 0x020180 yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : zebra_cv_ipv6=yes zebra_cv_linux_ipv6=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux IPv6" >&5 $as_echo "Linux IPv6" >&6; } fi rm -f conftest* else if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" then zebra_cv_ipv6=yes zebra_cv_linux_ipv6=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: Linux IPv6" >&5 $as_echo "Linux IPv6" >&6; } fi fi if test "$zebra_cv_linux_ipv6" = "yes";then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libc has IPv6 support" >&5 $as_echo_n "checking whether libc has IPv6 support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { int a; a = (int) in6addr_any.s6_addr[0]; if (a != 12345) return a; ; 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; } zebra_cv_ipv6=yes zebra_cv_linux_ipv6=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } zebra_cv_ipv6=no zebra_cv_linux_ipv6=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi if test "$zebra_cv_linux_ipv6" = "yes";then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc >= 2.1" >&5 $as_echo_n "checking for GNU libc >= 2.1... " >&6; } $as_echo "#define HAVE_IPV6 1" >>confdefs.h cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : glibc=yes $as_echo "#define LINUX_IPV6 1" >>confdefs.h { $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* RIPNGD="ripngd" OSPF6D="ospf6d" if test "$glibc" != "yes"; then INCLUDES="-I/usr/inet6/include" if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then LIB_IPV6="-L/usr/inet6/lib -linet6" fi fi fi LIBS="$LIB_IPV6 $LIBS" if test x"$RIPNGD" = x""; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: IPv4 only" >&5 $as_echo "IPv4 only" >&6; } fi fi if test "x${zebra_cv_ipv6}" = "xyes"; then 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 fi if test "${enable_doc}" = "no";then DOC="" else DOC="doc" fi if test "${enable_tests}" = "no";then BUILD_TESTS="" else BUILD_TESTS="tests" 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 "${enable_babeld}" = "no";then BABELD="" else BABELD="babeld" fi if test "x$BABELD" = "xbabeld"; then BABELD_TRUE= BABELD_FALSE='#' else BABELD_TRUE='#' BABELD_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_opaque_lsa}" != "no"; then if test "${enable_ospfapi}" != "no";then $as_echo "#define SUPPORT_OSPF_API /**/" >>confdefs.h if test "${enable_ospfclient}" != "no";then OSPFCLIENT="ospfclient" fi fi fi if test "x$OSPFCLIENT" = "xospfclient"; then OSPFCLIENT_TRUE= OSPFCLIENT_FALSE='#' else OSPFCLIENT_TRUE='#' OSPFCLIENT_FALSE= fi case "${enable_ripngd}" in "yes") RIPNGD="ripngd";; "no" ) RIPNGD="";; * ) ;; esac if test "x$RIPNGD" = "xripngd"; then RIPNGD_TRUE= RIPNGD_FALSE='#' else RIPNGD_TRUE='#' RIPNGD_FALSE= fi case "${enable_ospf6d}" in "yes") OSPF6D="ospf6d";; "no" ) OSPF6D="";; * ) ;; esac if test "x$OSPF6D" = "xospf6d"; then OSPF6D_TRUE= OSPF6D_FALSE='#' else OSPF6D_TRUE='#' OSPF6D_FALSE= fi case "${enable_isisd}" in "yes") ISISD="isisd";; "no" ) ISISD="";; * ) ;; esac if test "x$ISISD" = "xisisd"; then ISISD_TRUE= ISISD_FALSE='#' else ISISD_TRUE='#' ISISD_FALSE= fi # XXX Perhaps auto-enable on Solaris, but that's messy for cross builds. case "${enable_solaris}" in "yes") SOLARIS="solaris";; "no" ) SOLARIS="";; * ) ;; esac 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 ac_fn_c_check_func "$LINENO" "__inet_ntop" "ac_cv_func___inet_ntop" if test "x$ac_cv_func___inet_ntop" = xyes; then : $as_echo "#define HAVE_INET_NTOP /**/" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "__inet_pton" "ac_cv_func___inet_pton" if test "x$ac_cv_func___inet_pton" = xyes; then : $as_echo "#define HAVE_INET_PTON /**/" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "__inet_aton" "ac_cv_func___inet_aton" if test "x$ac_cv_func___inet_aton" = xyes; then : $as_echo "#define HAVE_INET_ATON /**/" >>confdefs.h 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_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 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 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 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 : ac_fn_c_check_func "$LINENO" "backtrace" "ac_cv_func_backtrace" if test "x$ac_cv_func_backtrace" = xyes; then : $as_echo "#define HAVE_GLIBC_BACKTRACE /**/" >>confdefs.h $as_echo "#define HAVE_STACK_TRACE /**/" >>confdefs.h 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'` # Check whether --enable-pie was given. if test "${enable_pie+set}" = set; then : enableval=$enable_pie; fi if test "$enable_pie" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts PIE flags" >&5 $as_echo_n "checking whether $CC accepts PIE flags... " >&6; } if ${ap_cv_cc_pie+:} false; then : $as_echo_n "(cached) " >&6 else save_CFLAGS=$CFLAGS save_LDFLAGS=$LDFLAGS CFLAGS="$CFLAGS -fPIE" LDFLAGS="$LDFLAGS -pie" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ static int foo[30000]; int main () { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ap_cv_cc_pie=yes else ap_cv_cc_pie=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$save_CFLAGS LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ap_cv_cc_pie" >&5 $as_echo "$ap_cv_cc_pie" >&6; } if test "$ap_cv_cc_pie" = "yes"; then PICFLAGS="-fPIE" PILDFLAGS="-pie" fi fi { $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_BABELD_PID "$quagga_statedir/babeld.pid" _ACEOF cat >>confdefs.h <<_ACEOF #define PATH_ISISD_PID "$quagga_statedir/isisd.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 BABEL_VTYSH_PATH "$quagga_statedir/babeld.vty" _ACEOF cat >>confdefs.h <<_ACEOF #define ISIS_VTYSH_PATH "$quagga_statedir/isisd.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 zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile redhat/Makefile pkgsrc/Makefile redhat/quagga.spec lib/version.h doc/defines.texi 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 "${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 "${BABELD_TRUE}" && test -z "${BABELD_FALSE}"; then as_fn_error $? "conditional \"BABELD\" 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 : "${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 0.99.22.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 0.99.22.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"`' 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_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"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $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"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $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_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ 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\\"\\\`\\\\\\"" ;; *) 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 \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which 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' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _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" ;; "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" ;; "babeld/Makefile") CONFIG_FILES="$CONFIG_FILES babeld/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" ;; "redhat/Makefile") CONFIG_FILES="$CONFIG_FILES redhat/Makefile" ;; "pkgsrc/Makefile") CONFIG_FILES="$CONFIG_FILES pkgsrc/Makefile" ;; "redhat/quagga.spec") CONFIG_FILES="$CONFIG_FILES redhat/quagga.spec" ;; "lib/version.h") CONFIG_FILES="$CONFIG_FILES lib/version.h" ;; "doc/defines.texi") CONFIG_FILES="$CONFIG_FILES doc/defines.texi" ;; "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"" || { # Autoconf 2.62 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 which 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 # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $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. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### 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 # 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 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 # 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 in which our libraries should be installed. lt_sysroot=$lt_sysroot # 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 # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # 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 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 "X${COLLECT_NAMES+set}" != Xset; 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) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi 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} includes : ${INCLUDES} 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} 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-0.99.22.4/configure.ac0000755000175000017500000015043512211704467012532 00000000000000## ## 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.53) AC_INIT(Quagga, 0.99.22.4, [https://bugzilla.quagga.net]) 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() AM_INIT_AUTOMAKE(1.6) 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], AC_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], AC_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 dnl autoconf 2.59 appears not to support AC_PROG_SED dnl AC_PROG_SED AC_CHECK_PROG([SED],[sed],[sed],[/bin/false]) dnl pdflatex and latexmk are needed to build HACKING.pdf 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 ------------------------------------------------------------------ dnl Intel compiler check. Although Intel tries really hard to make icc dnl look like gcc, there are some differences. It's very verbose with dnl -Wall and it doesn't support the individual -W options. dnl ------------------------------------------------------------------ if test "x${GCC}" = "xyes" ; then COMPILER="GCC" AC_MSG_CHECKING([whether we are using the Intel compiler]) AC_EGREP_CPP([^__INTEL_COMPILER], [__INTEL_COMPILER], [AC_MSG_RESULT([no])], [COMPILER="ICC" AC_MSG_RESULT([yes])] ) else AC_MSG_CHECKING([whether we are using SunPro compiler]) AC_EGREP_CPP([^__SUNPRO_C.*0x5(7|8|9)], ["__SUNPRO_C" __SUNPRO_C], [AC_MSG_RESULT([no])], [COMPILER="SUNPRO" AC_MSG_RESULT([yes])] ) 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 Intel icc 8.0 also sets __GNUC__, dnl but doesn't support all these fancy -W options. dnl Intel compiler warnings we ignore: dnl 279: controlling expression is constant. dnl 869: parameter "xxx" was never referenced - to avoid massive warnings dnl about "self", "vty", "argc" and "argv" never referenced in DEFUN dnl macro. dnl 981: operands are evaluated in unspecified order. dnl dnl Sun Studio 10 / SunPro 5.7 is also supported, dnl so lets set some sane CFLAGS for it. dnl --------------------------------------------- AC_MSG_CHECKING([whether to set a default CFLAGS]) if test "x${cflags_specified}" = "x" ; then case ${COMPILER} in "ICC") CFLAGS="-Os -g -Wall" AC_MSG_RESULT([Intel default]) ;; "GCC") CFLAGS="-Os -fno-omit-frame-pointer -g -std=gnu99 -Wall" CFLAGS="${CFLAGS} -Wsign-compare -Wpointer-arith" CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" CFLAGS="${CFLAGS} -Wmissing-prototypes -Wmissing-declarations" CFLAGS="${CFLAGS} -Wchar-subscripts -Wcast-qual" # TODO: conditionally addd -Wpacked if handled AC_MSG_RESULT([gcc default]) ;; "SUNPRO") CFLAGS="-xO4 -v -g -xspace -xcode=pic32 -xstrconst -xc99" AC_MSG_RESULT([SunPro default]) ;; *) AC_MSG_RESULT([unknown compiler]) ;; esac else AC_MSG_RESULT([CFLAGS supplied by user]) fi 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 libtool dnl ------- AC_PROG_LIBTOOL 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, [ --enable-vtysh include integrated vty shell for Quagga]) AC_ARG_ENABLE(ipv6, [ --disable-ipv6 turn off IPv6 related features and daemons]) AC_ARG_ENABLE(doc, [ --disable-doc do not build docs]) AC_ARG_ENABLE(tests, [ --disable-tests do not build tests]) AC_ARG_ENABLE(zebra, [ --disable-zebra do not build zebra daemon]) AC_ARG_ENABLE(bgpd, [ --disable-bgpd do not build bgpd]) AC_ARG_ENABLE(ripd, [ --disable-ripd do not build ripd]) AC_ARG_ENABLE(ripngd, [ --disable-ripngd do not build ripngd]) AC_ARG_ENABLE(ospfd, [ --disable-ospfd do not build ospfd]) AC_ARG_ENABLE(ospf6d, [ --disable-ospf6d do not build ospf6d]) AC_ARG_ENABLE(babeld, [ --disable-babeld do not build babeld]) AC_ARG_ENABLE(watchquagga, [ --disable-watchquagga do not build watchquagga]) AC_ARG_ENABLE(isisd, [ --enable-isisd build isisd]) AC_ARG_ENABLE(solaris, [ --enable-solaris build solaris]) AC_ARG_ENABLE(bgp-announce, [ --disable-bgp-announce, turn off BGP route announcement]) AC_ARG_ENABLE(netlink, [ --enable-netlink force to use Linux netlink interface]) AC_ARG_ENABLE(broken-aliases, [ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X]) AC_ARG_ENABLE(snmp, [ --enable-snmp=ARG enable SNMP support (smux or agentx)]) AC_ARG_WITH(libpam, [ --with-libpam use libpam for PAM support in vtysh]) AC_ARG_ENABLE(tcp-zebra, [ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon]) AC_ARG_ENABLE(opaque-lsa, AC_HELP_STRING([--disable-opaque-lsa],[do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370)])) AC_ARG_ENABLE(ospfapi, [ --disable-ospfapi do not build OSPFAPI to access the OSPF LSA Database]) AC_ARG_ENABLE(ospfclient, [ --disable-ospfclient do not build OSPFAPI client for OSPFAPI, (this is the default if --disable-ospfapi is set)]) AC_ARG_ENABLE(ospf-te, AC_HELP_STRING([--disable-ospf-te],[disable Traffic Engineering Extension to OSPF])) AC_ARG_ENABLE(multipath, [ --enable-multipath=ARG enable multipath function, ARG must be digit]) AC_ARG_ENABLE(user, AC_HELP_STRING([--enable-user=user], [user to run Quagga suite as (default quagga)])) AC_ARG_ENABLE(group, AC_HELP_STRING([--enable-group=group], [group to run Quagga suite as (default quagga)])) AC_ARG_ENABLE(vty_group, [ --enable-vty-group=ARG set vty sockets to have specified group as owner]) AC_ARG_ENABLE(configfile_mask, [ --enable-configfile-mask=ARG set mask for config files]) AC_ARG_ENABLE(logfile_mask, [ --enable-logfile-mask=ARG set mask for log files]) AC_ARG_ENABLE(rtadv, [ --disable-rtadv disable IPV6 router advertisement feature]) AC_ARG_ENABLE(irdp, [ --enable-irdp enable IRDP server support in zebra]) AC_ARG_ENABLE(isis_topology, [ --enable-isis-topology enable IS-IS topology generator]) AC_ARG_ENABLE(capabilities, [ --disable-capabilities disable using POSIX capabilities]) AC_ARG_ENABLE(rusage, [ --disable-rusage disable using getrusage]) AC_ARG_ENABLE(gcc_ultra_verbose, [ --enable-gcc-ultra-verbose enable ultra verbose GCC warnings]) AC_ARG_ENABLE(linux24_tcp_md5, [ --enable-linux24-tcp-md5 enable support for old, Linux-2.4 RFC2385 patch]) AC_ARG_ENABLE(gcc-rdynamic, [ --enable-gcc-rdynamic enable gcc linking with -rdynamic for better backtraces]) AC_ARG_ENABLE(time-check, [ --disable-time-check disable slow thread warning messages]) AC_ARG_ENABLE(pcreposix, [ --enable-pcreposix enable using PCRE Posix libs for regex functions]) AC_ARG_ENABLE(fpm, [ --enable-fpm enable Forwarding Plane Manager support]) if test x"${enable_gcc_ultra_verbose}" = x"yes" ; then CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" CFLAGS="${CFLAGS} -Wpacked -Wpadded" fi if test x"${enable_gcc_rdynamic}" = x"yes" ; then LDFLAGS="${LDFLAGS} -rdynamic" 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 "${enable_broken_aliases}" = "yes"; then if test "${enable_netlink}" = "yes" then AC_MSG_FAILURE([Sorry you can not use netlink with broken aliases]) fi AC_DEFINE(HAVE_BROKEN_ALIASES,,Broken Alias) enable_netlink=no fi if test "${enable_tcp_zebra}" = "yes"; then AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi if test "${enable_opaque_lsa}" != "no"; then AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) fi if test "${enable_ospf_te}" != "no"; then AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) AC_DEFINE(HAVE_OSPF_TE,,OSPF TE) 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}" = "yes" && 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 "${enable_user}" = "yes" || test x"${enable_user}" = x""; then enable_user="quagga" elif test "${enable_user}" = "no"; then enable_user="root" fi if test "${enable_group}" = "yes" || test x"${enable_group}" = x""; then enable_group="quagga" elif test "${enable_group}" = "no"; then enable_group="root" 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]) AC_DEFINE_UNQUOTED(QUAGGA_USER, "${enable_user}", Quagga User) AC_DEFINE_UNQUOTED(QUAGGA_GROUP, "${enable_group}", Quagga 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) MULTIPATH_NUM=1 case "${enable_multipath}" in [[0-9]|[1-9][0-9]]) MULTIPATH_NUM="${enable_multipath}" ;; "") ;; *) AC_MSG_FAILURE([Please specify digit to enable multipath ARG]) ;; esac AC_SUBST(MULTIPATH_NUM) 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 dnl AC_TYPE_PID_T AC_TYPE_UID_T AC_TYPE_MODE_T AC_TYPE_SIZE_T AC_TYPE_SIGNAL 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/param.h limits.h signal.h \ sys/socket.h netinet/in.h time.h sys/time.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([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 ;; [*-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 ;; *-sunos5* | *-solaris2*) AC_DEFINE(SUNOS_5,,SunOS 5, Unknown SunOS) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) CURSES=-lcurses ;; *-linux*) opsys=gnu-linux AC_DEFINE(GNU_LINUX,,GNU Linux) ;; *-nec-sysv4*) AC_CHECK_LIB(nsl, gethostbyname) AC_CHECK_LIB(socket, socket) ;; *-openbsd*) opsys=openbsd AC_DEFINE(OPEN_BSD,,OpenBSD) ;; *-bsdi*) opsys=bsdi OTHER_METHOD="mtu_kvm.o" AC_CHECK_LIB(kvm, main) ;; *-irix6.5) opsys=irix AC_DEFINE(IRIX_65,,IRIX 6.5) ;; esac AC_SYS_LARGEFILE dnl --------------------- dnl Integrated VTY option dnl --------------------- case "${enable_vtysh}" in "yes") 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="$LIBREADLINE -lreadline",, "$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]) AC_CHECK_FUNCS(setproctitle, , [AC_CHECK_LIB(util, setproctitle, [LIBS="$LIBS -lutil" AC_DEFINE(HAVE_SETPROCTITLE,, Have setproctitle) ] ) ] ) dnl ------------------------------------ dnl Determine routing get and set method dnl ------------------------------------ AC_MSG_CHECKING(zebra between kernel interface method) if test x"$opsys" = x"gnu-linux"; then if test "${enable_netlink}" = "yes";then AC_MSG_RESULT(netlink) RT_METHOD=rt_netlink.o AC_DEFINE(HAVE_NETLINK,,netlink) netlink=yes elif test "${enable_netlink}" = "no"; then AC_MSG_RESULT(ioctl) RT_METHOD=rt_ioctl.o netlink=no else AC_MSG_RESULT(netlink) RT_METHOD=rt_netlink.o AC_DEFINE(HAVE_NETLINK,,netlink) netlink=yes fi elif test x"$opsys" = x"sol2-6";then AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" elif test x"$opsys" = x"sol8";then AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" elif test "$opsys" = "irix" ; then AC_MSG_RESULT(Route socket) KERNEL_METHOD="kernel_socket.o" RT_METHOD="rt_socket.o" else AC_TRY_RUN([#include #include #include main () { int ac_sock; ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); if (ac_sock < 0 && errno == EINVAL) exit (1); exit (0); }], [KERNEL_METHOD=kernel_socket.o RT_METHOD=rt_socket.o AC_MSG_RESULT(socket)], [RT_METHOD=rt_ioctl.o AC_MSG_RESULT(ioctl)], [KERNEL_METHOD=kernel_socket.o RT_METHOD=rt_socket.o AC_MSG_RESULT(socket)]) fi AC_SUBST(RT_METHOD) AC_SUBST(KERNEL_METHOD) AC_SUBST(OTHER_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 /proc/net/route /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 "/proc/net/route") quagga_cv_rtread_method="proc";; "/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" = "irix" ; then AC_MSG_RESULT(IRIX) IF_METHOD=if_ioctl.o elif test "$opsys" = "openbsd";then AC_MSG_RESULT(openbsd) IF_METHOD=if_ioctl.o elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then AC_MSG_RESULT(sysctl) IF_METHOD=if_sysctl.o AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST) else AC_MSG_RESULT(ioctl) IF_METHOD=if_ioctl.o fi 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_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__) 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 proc file system. dnl ----------------------- if test "$netlink" != yes; then if test -r /proc/net/dev; then AC_DEFINE(HAVE_PROC_NET_DEV,,/proc/net/dev) IF_PROC=if_proc.o fi if test -r /proc/net/if_inet6; then AC_DEFINE(HAVE_PROC_NET_IF_INET6,,/proc/net/if_inet6) IF_PROC=if_proc.o fi fi AC_SUBST(IF_PROC) 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 *-nec-sysv4*) quagga_cv_ipforward_method="ews";; *-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) if test "${enable_ipv6}" = "no"; then AC_MSG_RESULT(disabled) else dnl ---------- dnl INRIA IPv6 dnl ---------- if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then zebra_cv_ipv6=yes AC_DEFINE(HAVE_IPV6,1,INRIA IPv6) AC_DEFINE(INRIA_IPV6,1,INRIA IPv6) RIPNGD="ripngd" OSPF6D="ospf6d" LIB_IPV6="" AC_MSG_RESULT(INRIA IPv6) dnl --------- dnl KAME IPv6 dnl --------- elif grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes AC_DEFINE(HAVE_IPV6,1,KAME IPv6) AC_DEFINE(KAME,1,KAME IPv6) RIPNGD="ripngd" OSPF6D="ospf6d" if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then LIB_IPV6="-L/usr/local/v6/lib -linet6" fi AC_MSG_RESULT(KAME) dnl ------------------------- dnl MUSICA IPv6 dnl default host check dnl It is not used by Kheops dnl ------------------------- elif grep MUSICA /usr/include6/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes AC_DEFINE(HAVE_IPV6,1,Musicia IPv6) AC_DEFINE(MUSICA,1,Musica IPv6 stack) AC_DEFINE(KAME,1,KAME IPv6 stack) RIPNGD="ripngd" OSPF6D="ospf6d" if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then LIB_IPV6="-L/usr/local/v6/lib -linet6" fi AC_MSG_RESULT(MUSICA) dnl --------- dnl NRL check dnl --------- elif grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes AC_DEFINE(HAVE_IPV6,1,NRL IPv6) AC_DEFINE(NRL,1,NRL) RIPNGD="ripngd" OSPF6D="ospf6d" if test x"$opsys" = x"bsdi";then AC_DEFINE(BSDI_NRL,,BSDI) AC_MSG_RESULT(BSDI_NRL) else AC_MSG_RESULT(NRL) fi dnl ------------------------------------ dnl Solaris 9, 10 and potentially higher dnl ------------------------------------ elif test x"$opsys" = x"sol8"; then zebra_cv_ipv6=yes; AC_DEFINE(HAVE_IPV6, 1, IPv6) AC_DEFINE(SOLARIS_IPV6, 1, Solaris IPv6) RIPNGD="ripngd" OSPF6D="ospf6d" AC_MSG_RESULT(Solaris IPv6) dnl ---------- dnl Linux IPv6 dnl ---------- elif test "${enable_ipv6}" = "yes"; then AC_EGREP_CPP(yes, [ #include /* 2.1.128 or later */ #if LINUX_VERSION_CODE >= 0x020180 yes #endif], [zebra_cv_ipv6=yes zebra_cv_linux_ipv6=yes AC_MSG_RESULT(Linux IPv6)]) else if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" then zebra_cv_ipv6=yes zebra_cv_linux_ipv6=yes AC_MSG_RESULT(Linux IPv6) fi fi if test "$zebra_cv_linux_ipv6" = "yes";then AC_MSG_CHECKING(whether libc has IPv6 support) AC_TRY_LINK([#include ],[ int a; a = (int) in6addr_any.s6_addr[0]; if (a != 12345) return a; ], [AC_MSG_RESULT(yes) zebra_cv_ipv6=yes zebra_cv_linux_ipv6=yes], [AC_MSG_RESULT(no) zebra_cv_ipv6=no zebra_cv_linux_ipv6=no]) fi if test "$zebra_cv_linux_ipv6" = "yes";then AC_MSG_CHECKING(for GNU libc >= 2.1) AC_DEFINE(HAVE_IPV6,1,Linux IPv6) AC_EGREP_CPP(yes, [ #include #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 yes #endif], [glibc=yes AC_DEFINE(LINUX_IPV6,1,Linux IPv6 stack) AC_MSG_RESULT(yes)], AC_MSG_RESULT(no) ) RIPNGD="ripngd" OSPF6D="ospf6d" if test "$glibc" != "yes"; then INCLUDES="-I/usr/inet6/include" if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then LIB_IPV6="-L/usr/inet6/lib -linet6" fi fi fi dnl ----------------------- dnl Set IPv6 related values dnl ----------------------- LIBS="$LIB_IPV6 $LIBS" AC_SUBST(LIB_IPV6) if test x"$RIPNGD" = x""; then AC_MSG_RESULT(IPv4 only) fi fi dnl ------------------ dnl IPv6 header checks dnl ------------------ if test "x${zebra_cv_ipv6}" = "xyes"; then AC_CHECK_HEADERS([netinet6/in6.h netinet/in6_var.h netinet/icmp6.h \ netinet6/in6_var.h netinet6/nd6.h], [], [], QUAGGA_INCLUDES) fi 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 can't use TESTS as name, that's special with automake if test "${enable_tests}" = "no";then BUILD_TESTS="" else BUILD_TESTS="tests" 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 "${enable_babeld}" = "no";then BABELD="" else BABELD="babeld" fi AM_CONDITIONAL(BABELD, test "x$BABELD" = "xbabeld") if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else WATCHQUAGGA="watchquagga" fi AM_CONDITIONAL(WATCHQUAGGA, test "x$WATCHQUAGGA" = "xwatchquagga") OSPFCLIENT="" if test "${enable_opaque_lsa}" != "no"; then if test "${enable_ospfapi}" != "no";then AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI) if test "${enable_ospfclient}" != "no";then OSPFCLIENT="ospfclient" fi fi fi AM_CONDITIONAL(OSPFCLIENT, test "x$OSPFCLIENT" = "xospfclient") case "${enable_ripngd}" in "yes") RIPNGD="ripngd";; "no" ) RIPNGD="";; * ) ;; esac AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd") case "${enable_ospf6d}" in "yes") OSPF6D="ospf6d";; "no" ) OSPF6D="";; * ) ;; esac AM_CONDITIONAL(OSPF6D, test "x$OSPF6D" = "xospf6d") case "${enable_isisd}" in "yes") ISISD="isisd";; "no" ) ISISD="";; * ) ;; esac AM_CONDITIONAL(ISISD, test "x$ISISD" = "xisisd") # XXX Perhaps auto-enable on Solaris, but that's messy for cross builds. case "${enable_solaris}" in "yes") SOLARIS="solaris";; "no" ) SOLARIS="";; * ) ;; esac 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(BUILD_TESTS) AC_SUBST(ZEBRA) AC_SUBST(BGPD) AC_SUBST(RIPD) AC_SUBST(RIPNGD) AC_SUBST(OSPFD) AC_SUBST(OSPF6D) AC_SUBST(BABELD) AC_SUBST(WATCHQUAGGA) AC_SUBST(ISISD) AC_SUBST(SOLARIS) AC_SUBST(VTYSH) AC_SUBST(INCLUDES) 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 BSD/OS 4.1 define inet_XtoY function as __inet_XtoY dnl --------------------------------------------------- AC_CHECK_FUNC(__inet_ntop, AC_DEFINE(HAVE_INET_NTOP,,__inet_ntop)) AC_CHECK_FUNC(__inet_pton, AC_DEFINE(HAVE_INET_PTON,,__inet_pton)) AC_CHECK_FUNC(__inet_aton, AC_DEFINE(HAVE_INET_ATON,,__inet_aton)) 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 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 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 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 --------------------------- AC_CHECK_HEADER([execinfo.h], [AC_CHECK_FUNC([backtrace], [AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) ]) ]) 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 Conditionally enable PIE support for GNU toolchains. AC_ARG_ENABLE(pie, AS_HELP_STRING([--disable-pie], [Do not build tools as a Position Independent Executables])) if test "$enable_pie" != "no"; then AC_CACHE_CHECK([whether $CC accepts PIE flags], [ap_cv_cc_pie], [ save_CFLAGS=$CFLAGS save_LDFLAGS=$LDFLAGS CFLAGS="$CFLAGS -fPIE" LDFLAGS="$LDFLAGS -pie" AC_LINK_IFELSE([AC_LANG_SOURCE([[static int foo[30000]; int main () { return 0; }]])], [ap_cv_cc_pie=yes], [ap_cv_cc_pie=no] ) CFLAGS=$save_CFLAGS LDFLAGS=$save_LDFLAGS ]) if test "$ap_cv_cc_pie" = "yes"; then PICFLAGS="-fPIE" PILDFLAGS="-pie" fi fi AC_SUBST(PICFLAGS) AC_SUBST(PILDFLAGS) 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_BABELD_PID, "$quagga_statedir/babeld.pid",babeld PID) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd 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(BABEL_VTYSH_PATH, "$quagga_statedir/babeld.vty",babeld vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd 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 zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile redhat/Makefile pkgsrc/Makefile redhat/quagga.spec lib/version.h doc/defines.texi 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} includes : ${INCLUDES} 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} 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-0.99.22.4/depcomp0000755000175000017500000005654612070614057011624 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2012-07-12.20; # UTC # Copyright (C) 1999-2012 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 # A tabulation character. tab=' ' # A newline character. nl=' ' 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 -eq 0; then : else 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 -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' "$nl" < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. 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. 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 -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$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 # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; 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. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$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 -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependent.h'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. # However on # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\': # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... # tcc 0.9.26 (FIXME still under development at the moment of writing) # will emit a similar output, but also prepend the continuation lines # with horizontal tabulation characters. "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else 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 -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ < "$tmpdepfile" > "$depfile" sed ' s/[ '"$tab"'][ '"$tab"']*/ /g s/^ *// s/ *\\*$// s/^[^:]*: *// /^$/d /:$/d s/$/ :/ ' < "$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 ... \ # ... dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. base=`echo "$source" | sed -e 's|^.*/||' -e 's/\.[-_a-zA-Z0-9]*$//'` 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; rm -rf $lockdir" 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. rm -rf $lockdir break else ## 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. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else 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,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#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. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # 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.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; 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" = 0; then : else 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" 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" tr ' ' "$nl" < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # 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" sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the 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-0.99.22.4/doc/0000755000175000017500000000000012211704577011060 500000000000000quagga-0.99.22.4/doc/BGP-TypeCode0000644000175000017500000000175212101110036013025 00000000000000 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-0.99.22.4/doc/Makefile.am0000644000175000017500000000575712177450262013052 00000000000000## 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 \ _topologies_full _topologies_rs 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. # Built from defines.texi.in BUILT_SOURCES = defines.texi info_TEXINFOS = quagga.texi # Have to manually specify the quagga.pdf rule in order to allow # us to have a generic automatic .pdf rule to build the figure sources # because it cant just work from the png's directly it seems - contrary # to the documentation... quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) $(TEXI2PDF) -o "$@" $< quagga_TEXINFOS = appendix.texi babeld.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 $(figures_txt) .png.eps: $(PNGTOEPS) $< "$@" .png.pdf: $(PNGTOPDF) $< "$@" .dia.png: $(DIATOPNG) "$@" $< man_MANS = 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 VTYSH man_MANS += vtysh.1 endif if WATCHQUAGGA man_MANS += watchquagga.8 endif if ZEBRA man_MANS += zebra.8 endif 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 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) draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ quagga-0.99.22.4/doc/Makefile.in0000644000175000017500000007467312211704501013051 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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@ @BGPD_TRUE@am__append_1 = bgpd.8 @ISISD_TRUE@am__append_2 = isisd.8 @OSPF6D_TRUE@am__append_3 = ospf6d.8 @OSPFCLIENT_TRUE@am__append_4 = ospfclient.8 @OSPFD_TRUE@am__append_5 = ospfd.8 @RIPD_TRUE@am__append_6 = ripd.8 @RIPNGD_TRUE@am__append_7 = ripngd.8 @VTYSH_TRUE@am__append_8 = vtysh.1 @WATCHQUAGGA_TRUE@am__append_9 = watchquagga.8 @ZEBRA_TRUE@am__append_10 = zebra.8 subdir = doc DIST_COMMON = $(quagga_TEXINFOS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/defines.texi.in \ $(srcdir)/stamp-vti $(srcdir)/version.texi mdate-sh \ texinfo.tex 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = defines.texi CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = INFO_DEPS = $(srcdir)/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 AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) 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) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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 \ _topologies_full _topologies_rs 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. # Built from defines.texi.in BUILT_SOURCES = defines.texi info_TEXINFOS = quagga.texi quagga_TEXINFOS = appendix.texi babeld.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 $(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) 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 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) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .png .eps .dia .pdf .dvi .html .info .ps .texi $(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 .PRECIOUS: 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): defines.texi: $(top_builddir)/config.status $(srcdir)/defines.texi.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs .texi.info: restore=: && backupdir="$(am__leading_dot)am$$$$" && \ am__cwd=`pwd` && $(am__cd) $(srcdir) && \ 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 && \ cd "$$am__cwd"; \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ $<; \ then \ rc=0; \ $(am__cd) $(srcdir); \ else \ rc=$$?; \ $(am__cd) $(srcdir) && \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc .texi.dvi: TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) --clean $< .texi.pdf: TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) --clean $< .texi.html: rm -rf $(@:.html=.htp) if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) $<; \ then \ rm -rf $@; \ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \ else \ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \ exit 1; \ fi $(srcdir)/quagga.info: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) quagga.dvi: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) quagga.html: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) $(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) -@rm -f vti.tmp @cp $(srcdir)/version.texi $@ mostlyclean-vti: -rm -f vti.tmp maintainer-clean-vti: -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi .dvi.ps: TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(DVIPS) -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.aux quagga.cp quagga.cps quagga.fn quagga.fns quagga.ky \ quagga.kys quagga.log quagga.pg quagga.pgs quagga.tmp \ quagga.toc quagga.tp quagga.tps quagga.vr quagga.vrs 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 TAGS: ctags: CTAGS CTAGS: cscope cscopelist: distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the 'missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically 'make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi @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: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) 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: $(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-aminfo clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am 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: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-aminfo clean-generic \ clean-libtool 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 uninstall uninstall-am uninstall-dvi-am \ uninstall-html-am uninstall-info-am uninstall-man \ uninstall-man1 uninstall-man8 uninstall-pdf-am uninstall-ps-am # Have to manually specify the quagga.pdf rule in order to allow # us to have a generic automatic .pdf rule to build the figure sources # because it cant just work from the png's directly it seems - contrary # to the documentation... quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) $(TEXI2PDF) -o "$@" $< .png.eps: $(PNGTOEPS) $< "$@" .png.pdf: $(PNGTOPDF) $< "$@" .dia.png: $(DIATOPNG) "$@" $< draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ # 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-0.99.22.4/doc/appendix.texi0000644000175000017500000002556112000052240013467 00000000000000@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, `subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP (version 4) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Old State | New State | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example Where State is the value defined in RFC1771. If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP version 6 @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Old State | New State | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, and Address Family == IP (version 4) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Message Packet | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example Where BGP Message Packet is the whole contents of the BGP4 message including header portion. If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, and Address Family == IP version 6 @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Message Packet | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, and Address Family == IP (version 4) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | Status | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time Last Change | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Family | SAFI | Next-Hop-Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Prefix Length | Address Prefix [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Attribute Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Attribute [variable length] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, and Address Family == IP version 6 @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | Status | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time Last Change | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Family | SAFI | Next-Hop-Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Prefix Length | Address Prefix [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Prefix (cont'd) [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Attribute Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Attribute [variable length] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example BGP4 Attribute must not contain MP_UNREACH_NLRI. If BGP Attribute has MP_REACH_NLRI field, it must has zero length NLRI, e.g., MP_REACH_NLRI has only Address Family, SAFI and next-hop values. If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT, @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | File Name [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example The file specified in "File Name" contains all routing entries, which are in the format of ``subtype == BGP4MP_ENTRY''. @example @group Constants: /* type value */ #define MSG_PROTOCOL_BGP4MP 16 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3 @end group @end example quagga-0.99.22.4/doc/babeld.texi0000644000175000017500000001070412177450262013106 00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node Babel @chapter Babel Babel is an interior gateway protocol that is suitable both for wired networks and for wireless mesh networks. Babel has been described as ``RIP on speed'' --- it is based on the same principles as RIP, but includes a number of refinements that make it react much faster to topology changes without ever counting to infinity, and allow it to perform reliable link quality estimation on wireless links. Babel is a double-stack routing protocol, meaning that a single Babel instance is able to perform routing for both IPv4 and IPv6. Quagga implements Babel as described in RFC6126. @menu * Configuring babeld:: * Babel configuration:: * Babel redistribution:: * Show Babel information:: * Babel debugging commands:: @end menu @node Configuring babeld, Babel configuration, Babel, Babel @section Configuring babeld The @command{babeld} daemon can be invoked with any of the common options (@pxref{Common Invocation Options}). The @command{zebra} daemon must be running before @command{babeld} is invoked. Also, if @command{zebra} is restarted then @command{babeld} must be too. Configuration of @command{babeld} is done in its configuration file @file{babeld.conf}. @node Babel configuration, Babel redistribution, Configuring babeld, Babel @section Babel configuration @deffn Command {router babel} {} @deffnx Command {no router babel} {} Enable or disable Babel routing. @end deffn @deffn {Babel Command} {network @var{ifname}} {} @deffnx {Babel Command} {no network @var{ifname}} {} Enable or disable Babel on the given interface. @end deffn @deffn {Interface Command} {babel wired} {} @deffnx {Interface Command} {babel wireless} {} Specifies whether this interface is wireless, which disables a number of optimisations that are only correct on wired interfaces. Specifying @code{wireless} (the default) is always correct, but may cause slower convergence and extra routing traffic. @end deffn @deffn {Interface Command} {babel split-horizon} @deffnx {Interface Command} {no babel split-horizon} Specifies whether to perform split-horizon on the interface. Specifying @code{no babel split-horizon} (the default) is always correct, while @code{babel split-horizon} is an optimisation that should only be used on symmetric and transitive (wired) networks. @end deffn @deffn {Interface Command} {babel hello-interval <20-655340>} Specifies the time in milliseconds between two scheduled hellos. On wired links, Babel notices a link failure within two hello intervals; on wireless links, the link quality value is reestimated at every hello interval. The default is 4000@dmn{ms}. @end deffn @deffn {Interface Command} {babel update-interval <20-655340>} Specifies the time in milliseconds between two scheduled updates. Since Babel makes extensive use of triggered updates, this can be set to fairly high values on links with little packet loss. The default is 20000@dmn{ms}. @end deffn @deffn {Babel Command} {babel resend-delay <20-655340>} Specifies the time in milliseconds after which an ``important'' request or update will be resent. The default is 2000@dmn{ms}. You probably don't want to tweak this value. @end deffn @node Babel redistribution, Show Babel information, Babel configuration, Babel @section Babel redistribution @deffn {Babel command} {redistribute @var{kind}} @deffnx {Babel command} {no redistribute @var{kind}} Specify which kind of routes should be redistributed into Babel. @end deffn @node Show Babel information, Babel debugging commands, Babel redistribution, Babel @section Show Babel information @deffn {Command} {show babel database} {} @deffnx {Command} {show babel interface} {} @deffnx {Command} {show babel neighbour} {} @deffnx {Command} {show babel parameters} {} These commands dump various parts of @command{babeld}'s internal state. They are mostly useful for troubleshooting. @end deffn @node Babel debugging commands, , Show Babel information, Babel @section Babel debugging commands @deffn {Babel Command} {debug babel @var{kind}} {} @deffnx {Babel Command} {no debug babel @var{kind}} {} Enable or disable debugging messages of a given kind. @var{kind} can be one of @samp{common}, @samp{kernel}, @samp{filter}, @samp{timeout}, @samp{interface}, @samp{route} or @samp{all}. Note that if you have compiled with the NO_DEBUG flag, then these commands aren't available. @end deffn quagga-0.99.22.4/doc/basic.texi0000644000175000017500000003755112116530242012755 00000000000000@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 * Terminal Mode Commands:: Common commands used in a VTY * Config Commands:: Commands used in config files * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons @end menu @node Config Commands @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 {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. @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 ? You can use command line help by typing @code{help} at the beginning of the line. Typing @kbd{?} at any point in the line will show possible completions. @end table quagga-0.99.22.4/doc/bgpd.80000644000175000017500000000547312000052240011771 00000000000000.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 \-dhrv ] [ .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\-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 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-0.99.22.4/doc/bgpd.texi0000644000175000017500000014745712177450262012631 00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @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 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. @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. @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 @table @asis @item 1. Weight check @item 2. Local preference check. @item 3. Local route check. @item 4. AS path length check. @item 5. Origin check. @item 6. MED check. @end table @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 @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 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 inlucde AS set. @end deffn @deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {} This command specifies an aggregate address. Aggreated routes will not be announce. @end deffn @deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {} @end deffn @node Redistribute to BGP @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} {} @deffnx {BGP} {no neighbor @var{peer} next-hop-self} {} This command specifies an announced route's nexthop as being equivalent to the address of the bgp router. @end deffn @deffn {BGP} {neighbor @var{peer} update-source @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 @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 @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 @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}} {} @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 or 0:90. Network operator can put special internal communities value at BGP border router, then limit the BGP routes announcement into the internal network. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list 1 permit 0:80 0:90 ! route-map RMAP permit in match community 1 @end example Following exmaple filter BGP routes which has communities value 1:1. When there is no match community-list returns deny. To avoid filtering all of routes, we need to define permit any at last. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list standard FILTER deny 1:1 ip community-list standard FILTER permit ! route-map RMAP permit 10 match community FILTER @end example Communities value keyword @code{internet} has special meanings in standard community lists. In below example @code{internet} act as match any. It matches all of BGP routes even if the route does not have communities attribute at all. So community list @code{INTERNET} is same as above example's @code{FILTER}. @example ip community-list standard INTERNET deny 1:1 ip community-list standard INTERNET permit internet @end example Following configuration is an example of communities value deletion. With this configuration communities value 100:1 and 100:2 is removed from BGP updates. For communities value deletion, only @code{permit} community-list is used. @code{deny} community-list is ignored. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list standard DEL permit 100:1 100:2 ! route-map RMAP permit 10 set comm-list DEL delete @end example @c ----------------------------------------------------------------------- @node BGP Extended Communities Attribute @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}} {} @deffnx Command {dump bgp all @var{path} @var{interval}} {} Dump all BGP packet and events to @var{path} file. @end deffn @deffn Command {dump bgp updates @var{path}} {} @deffnx Command {dump bgp updates @var{path} @var{interval}} {} Dump BGP updates to @var{path} file. @end deffn @deffn Command {dump bgp routes @var{path}} {} @deffnx Command {dump bgp routes @var{path}} {} Dump whole BGP routing table to @var{path}. This is heavy process. @end deffn @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-0.99.22.4/doc/defines.texi0000644000175000017500000000077312211704553013311 00000000000000@c -*- texinfo -*- @c doc/defines.texi. Generated from defines.texi.in by configure. @c Set variables @set PACKAGE_NAME Quagga @set PACKAGE_TARNAME quagga @set PACKAGE_STRING Quagga 0.99.22.4 @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-0.99.22.4/doc/defines.texi.in0000644000175000017500000000074012000052240013671 00000000000000@c -*- texinfo -*- @c @configure_input@ @c Set variables @set PACKAGE_NAME @PACKAGE_NAME@ @set PACKAGE_TARNAME @PACKAGE_TARNAME@ @set PACKAGE_STRING @PACKAGE_STRING@ @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-0.99.22.4/doc/draft-zebra-00.ms0000644000175000017500000001213512000052240013734 00000000000000.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-0.99.22.4/doc/draft-zebra-00.txt0000644000175000017500000001316512131557606014165 00000000000000 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-0.99.22.4/doc/fig-normal-processing.dia0000644000175000017500000017005612000052240015650 00000000000000 #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-0.99.22.4/doc/fig-normal-processing.png0000644000175000017500000007240612000052240015677 00000000000000‰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-0.99.22.4/doc/fig-normal-processing.txt0000644000175000017500000000102512000052240015717 00000000000000 _______________________________ / _________ _________ \ 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-0.99.22.4/doc/fig-rs-processing.dia0000644000175000017500000045232612000052240015007 00000000000000 #A4# #Best Path Selection# #Main Loc-RIB# #From Peer A# #From RS-Client B# #D# #C# #B# #A# #X# #“Out†Filter for Peer X# ## #“In†Filter for Peer X# #X# #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# ## #Export Policy of RS-Client X# #X# ## #Import Policy of RS-Client X# #X# #To RS-Client B# #B# #C# #To RS-Client C# #A# #To Peer A# #D# #To RS-Client D# quagga-0.99.22.4/doc/fig-rs-processing.png0000644000175000017500000023426012000052240015031 00000000000000‰PNG  IHDR]…tJsBITÛáOà pHYsÐй‹çŸ IDATxœìÝy\Tåþðï9³Á0þ Ë "(.l˜šW#S£Ô_æRJ†{YŠIiÛ ­0o–•׺®å–¦¦eš[.e*ŠÄ"« ÃḬ̂Ìz~œ`fàû~Ý×}Îò<ÏÊÇç< AQ d~äryBBµk×òòò²³³ ^¾¯¯¯··wDDD\\‡Ã1xù!„P¯C`.DfèìÙ³111"‘Èu …Â;vDFFš .„BÈœa.Dfçüùó‘‘‘Ey2™q¶¶L¦Ák)R©®56&ÔÔªTAœ={vÒ¤I¯!„êE0"ó"‘HE"Ñ>“ƒiäê4k++÷J¥B¡0--ÍÚÚÚÈ"„BæËØ¿vêœ-[¶ˆD¢`'Áø¡H€‡`G$mÙ²Åø"„Bæ s!2/ýõ¬´±a˜ªFÀJmÕ!„P¿…¹™…B#ØlSVJWWRRbÊJB!sƒã ‘y!ʽ¼L\¯SAà„Býö"„B!Ì…!„BˆÖÝ\H´2mÚ4ƒ´LŸI’´³³‹ŠŠzðà‘ªËÍÍ%bæÌ™F*!„BÈL`¹àS§Ny{{k¿´²²ê~™úÔHQT]]]VVV||üÒ¥KOžøàƒ7Ž?bccóóó“““Ï;wìØ±­[·jo‹‹‹[·n݆ Þzë­èèèÕ«W'$$9räâÅ‹ú4àܹsÇŠ¢¢¢¢ª««ÓÓÓ322D"ѲeËÚ9ߺ‘-ìÛ·oĈC† ™={ö… Z|:Ô>‚iÉó[òòD“¥ÃC2()ꧺ:c×…Bõ1Ý]¿^m®9mAìܹsáÂ… P(lmm¯^½ûöíÛ´iSjj*}Û¾}ûæÍ›§R©X,VóãÝ»w·~uKÄ•+W|}}5MEEʼn'6nÜxøðᨨ¨ëׯ‡‡‡'&&†††ÀîÝ»—,Y"“É’““užg³ÙÍÙ‚J¥òððxã7Þzë­”””ààà/¾øbåÊ•Ýùvõ7”ªAük¤F^¥=Ãq kÿÍrwÖ/ÌV*#Š‹™¡¢¨Pç´««þÏâú…!„Æfdd´5¾0""‚>‰D ô—™™™ÚÛè°Èd2[·eܸqôMhhè‰'žzê)HOO€Ù³gÓK¥R¥RYQQÑÖy77·æláâÅ‹b±xüøñ¥¥¥`À€Ä\Ø)t—¡$u³öŒ¼òš¢¨Öúk+‰²Ùlضm›³³³ö¤““S[çÛ¯…ž‰Ü<5Þ¿?//¯ùäkÔ!«A³eY»šw‚qÒ¡à°LÆ#Ékëkç×Õ½mkkÂB¡þÀDëZ{xxp¹\ºßRSSýüü ^KXX”——l†Åbµu¾¢êëë;¶sçNê¡üü|8xð Á›Ý·iG¶fØq‡WJÔêVV–1—Ç€#2Î=A!„ôg¢þB‹µ`Á‚ØØØíÛ·K$’øøø+V¼??¿Ù³g¿þúë$I>þøãõõõ7oÞœ1cF[çÛYjñäÉ“J¥²ùrÖ^^^cÇŽ=pàÀºuëºÐÙùàÈÐ.~ª¾ÎP}‡ôKä9<<ÅåÚ‘¤H¥ºÞØaa¡!ÒŒox¾ó ¦e—›Bõ^¦ÛoóæÍB¡0((èÉ'Ÿ|þùç4PoÏž=‹-Z»ví€"""¾ÿþ{z&A[çÛ²ÿþ¨¨¨ Y¿øâ‹éééôtdXھî=.Ñh~©¯Ìb…p8À&ˆ™<<œž¬?iÚVñ©‰²Œo)eçD!„ú€îÎGFzÂþB}pœÂ'ì…ÎÏGÞ'•®ª¬|ßÎîÕ‡Qþ®Bñ¯¬H2C(´Ô£—ž\|xý%É¶á Ž¶ò™K°xj B!Ô{a.4Ì…íÓ¾GîÚ:5SKJnÊå:/mwrš©ÇÞŒ-r! Ó!B¡~s¡)9:’Ò(écî€(ÛQ÷l{ E–µ»ùR5-´YØ…\˜¯TŽ*.摤€Áh~¾V£)W«'XZvqé°:–ü®QÔ¶¸Ô”}çL£ïýBõ Í;Aý¥jeíÒyÉPëÔª«€wíìòùÍÏÿ­P<ñàÁ円RµºEdl‹Ë”³²ì}uÙ{5 ‰ö¤FQ+IûBvo/oðL‡!„ú0ÓÍ;AýS]î¡‹=Žð‰=Oìé~(Ô–ÉX1½ÕËâ¡lv ›­8ª÷ì‚ÅãYê<åèk$Ûú‘Š5’´/ħ"eßR*Üd!„P„¹QëÎB&BÚŸE*ÕS––v¤ŽæÙ<üPWשѤ>é0ó˜Bõ1˜ ‘5ï,4x"¤ÑËÎâéž2ÓÊŠI EšBÑÙ’›¥ÃWu¤Ã»Ÿc:D!ÔÇà¼3ÒÇæPªñ¯‘yU§Ævm>r÷ÑóNÚúã QÊ겿¯Ëþ®ù¸CɶåùE[ùÌÅq‡!„z;ì/DÆR—{ˆe=È}„¦G²xü!ËšúYÌniê;üõ)Yæì;D!Ô«a¡écý…*IÓÚ§³O™gas¥¬.û»º{ßi”Ò—HŽ]Óz‡L®1‰Bö"céB(ìH?d¹óÔsü¡+ZöÊ«%w·ˆ”eî Tõ=ÕB„B¨k0"Ô$‹¯G:܉é!„P/‚¹¡®û'Y®+~†é!„P/‚¹¡î"Y|þИBõv˜ ‘y™0a©T¦¬”®nøðáÝ)äÑtøÈzŠÿ¤Ã¬]˜B™-̅ȼ°Ùl¸Óùe¨»ƒ®ÎÕÕµûE=L‡çùC–éH‡©ÿy˜º_B!dX˜ ‘y €­µµjSÕ¨ØZ[«­Ú HŸ?ôUç)çÚN‡Ob:D!dnpýB3ÒÇÖ/ì‰D(‰ðù›Œý ÀÚÊʽR©P(LKK³¶¶îø™ÎV¡ÔeW—ý½F)kq‰äØñü^±4›`Z¼^„B¨³°¿™kkë]»v±W* +*:,“i¬a‘JuX& +*Ú+•±k×.c„B ÙÖû—êê;Ü,þ5R–µûBõ8ì/4#Ø_¨uöìÙ˜˜‘Hd‚º„BáŽ;"##MP—F!©ËÞ[—½OWß¡=Ïo!ö"„êA˜ ÍæÂæäryBBµk×òòò²³³ ^¾¯¯¯··wDDD\\‡Ã1xùí Ó¡,{…é!„9Á\hF0ö+Emݽ½²œý˜B™ _ˆPÏ Ù6üÀ•.SÎò–-ÇVý3îPÝØS-D!Ôß`.D¨'é•ïíÁtˆBÈ0"Ôó´é°¸e:l¬”ÜùÓ!B!À\ˆ¹ Ù6Ö¯c:D!ÔS0"d^I‡L«æ—š¥Ã½˜BæB„ÌQS:œÚV:Ü„é!„Áa.DÈ|‘lÛŽÒáSu÷¾ÃtˆBÈ 0"dîþI‡þ‹Z¥ÃŠÚ; ˜BæB„z’mk=ì =Ò¡¼§ZˆB¨·Ã\ˆPo¢G:Œ¬ËþÓ!B¡.À\ˆPïÓ”§üÆóÑ‘o‚é!„P`.D¨·"9vÖÃV=L‡Üæ—ètXöëS˜Bés!B½ÛÃtx¶u:T7–?L‡û0"„êæB„ú‚féð]éðcL‡!„:„¹¡¾ƒäØY[é!„P×`.D¨¯é8žžŒé!„Pk˜ ê›þI‡~ [¦Ã†2L‡!„ZÃ\ˆÌ”\.ÿðÃ'OžîÙöô ³gÏÆÄĈD"Ô% wìØi‚ºz–F^-ËÚU—{R5´¸Ä°tæùÇpþÁàôHÛB™Ì…fs!íüùó‘‘‘Ey2™q¶¶L¦Ák)R©®56&ÔÔªTAœ={vÒ¤I¯Å iäÕ²¬u¹‡0"„js¡Á\‰$00P$-àó798{ ƒ`meå^©T(¦¥¥Y[[¹Bs¡‘Wɲva:D!ÔŽ/DæeË–-"‘(˜ÃI0~( ÁÁ!˜Ã‰D[¶l1~…æ‚äØ[_ã2å,ÏïeãS>*;=¹.çŽ;D¡~Åð¯çꎿþú VÚØ0LU#`¥MtY]u¿B§CžßÂÖ}‡ê†²Ú”²ÌÿñüqÎ4Hß!AÝ/õ1øÎ !³‚ý…ȼ( Áf›²Rº:ºê~¨£¾ÃM}‡š~úýA¡þÇš_»”ʽ¼L\¯SA`×…vÜaÎAJÝØâÃ҅翈ë=“ õMírñ_—pí—ôÜ~õ¾µcÕªU€è23Ø_ˆúÇ?}‡ƒ£ †EóKêqmʆ²_'×åÔ³ïP^v½.{ŸqZŠBÈðú~.,))‰ŽŽîéV Ô›Ö#Þ4H:”¤nVVÿm´–"„2$Zo1mÚ4£ÖÚ¼.‹rùòåæ7äååýßÿýŸ££#I’ÖÖÖÁÁÁÛ·oo§Àêêê7ß|ÓÇLJÉdZXXøùùÍ›7ÞÇ¢¶¶vïÞ½™™iðaïÚOÁf³‡þÓO?¶|„z^é0÷PûéÒ(«þZ­QJÜX„BÐ4ùÔ©SÞÞÞÚ³VVVÆ®˜®Q£ÑˆÅ⯿þzÆŒ%%%l64ÍäÉ“CBBNœ8acc#‹oܸQYYÙVQUUUááávvv ¾¾¾µµµIII§OŸV©TÎ?“(œœ>ýôÓ®µö½÷Þ[±b…‹‹‹ÎâååUSS³k×®yóæ•——s¹ÜÖ·õC×óÿzl`xÇ÷!óF§CžßBYÖκÜš;T7ˆk“ãÎYžÑÖ¸Cu]QMâ;ö_˜ªÉ!„ºˆ (Š ˆŒŒ ÓÕúh‰ÄÆÆ&;;ÛÇÇòóó½½½e2™žñôµ×^KLL¼|ùr󨕙™ÐÍ¡Ím}‹šŸ¯¯¯·²²ºw¯o×jécóNÞÚÿWþŸ/‡ÇyëÿÎ;1gšÆÊÖéÆà Z§CÉÝ-²Ìô±MÐ:žï‹€óNÐC8ï!3ÔÁøB‚ <èîî¾gϨ««‹ŽŽ¶²²²··ûí·5ö¶sçÎr¹ÜÍ›7—””„„„°X¬Y³f©TªQUUE„ƒƒý¥ƒÁ¸pá‚>€¢¨ƒ®_¿^g(l®ù{ä²²²9sæX[[s¹Ü™3gVTTh?HrròâÅ‹y<ž““ÓáÇ€N«íS¬¨¨`2™:ûû§é#fTæ¯<¼|å‘å)EÉÆ«È©  ùÿ¼ '=x°µ¶V‰¿o ´p°±ÖeÊo¼Á Z¾Y®/­MŽ/;ýt]î:ß,Kîl1Ȳõy„Bæ£)–———6ÓüŽ>ø`ãÆãÇ€ØØØüüüäääsçÎ;vlëÖ­ÚÛâââÖ­[·aÆ·Þz+::zõêÕ G޹xñb[uSÕÐÐpóæÍùóçÏ™3ÇÎÎŽ>okk»nݺçž{îÙgŸýᇤÒöF&•””TVV†‡wâ}%EQQQQÕÕÕééé"‘hÙ²eÚ«ÑÑÑ2™ìèÑ£sæÌY³f ܼy®]»öå—_ê,P­VgffÆÄĬY³¦ÿl¤Ö! –åœÐ E”l‚t¸€ÏŸÏçÏæñ†±Ùi E|uõ{ÕÕÆ«®?#-éth5x¾®tø¡ÎtHiÛßpçsûþ\7„꽚Þ#·8«íØ'bçÎ .…Bakk{õêÕØ·oߦM›RSSéÛöíÛ7oÞ<•JÅb±šïÞ½»u7[‹Ÿ}öÙC‡YX<ò æäÉ“[¶l¹|ù²¥¥eLL̆ ø|~ë••åïï¯R© Ýdhß#k®_¿ž˜˜ »wï^²d‰L&c³ÙA¼ùæ› A¤¦¦Ž1‚þV´óY{úØ{dhT6ÌÚ9£ºþŸ|$ nÿÍrÞ#Ó¯€›?r±¡á±Ø–$³==;U¾Òê,Mc…4kg}î­wÌcpLþ ¹øÏæ'½!‘yÄš°È|á{d„ÌPÓ¿Ý322¨fšßAˆD¢†††ÀÀ@úËÀÀÀÌÌLímtXd2™-ŽÛråÊ•’’’’’’ˆˆˆ´´´ÖÙ4**ê÷ßðàA||ü?üðì³ÏÒ Û±c‡vpNNÇ€êÎô ¥§§ÀìÙ³ýýýýýýßyç¥R©}•¼páBº1lý¶ÜÈÈÈP«Õååå«W¯~úé§÷ï߯Kú£R©ZôYº¹¹ÁÃ`Êår1™L’$gÍšõþûï·†¨Ñh4mt………@yyùÈfX,VûíÔçeÇÀÄbq‡wö­» µŒ”3Š×**H€u¶¶,uˆN‡ÎS~k?’„:Üþ‹ÄÝ–BÈì´÷ª·‹µ`Á‚ØØØíÛ·K$’øøø+V¤}ôÑ?þ÷ý÷ß@NNÎÌ™3çÌ™.$ÉçŸ>fÌ:¶?zôè°°°ØØØÀÀÀÆÆÆÄÄÄ={ö\»vÍVW2ðóó›={ö믿N’äã?^__óæÍ3f´³,Ž££cRR’P(¤_[7———GQ”B¡())Ù½{·»»»§®1mc?{¬ÃïÃ~%óaìoé¿~õÇï>Ò¤ˆ’SDË;wØ¡ðâb @FS¥VäpŽ ŽXÕÇú“q!žaAÂ`/‡xô~‚aáÄX¢ªÍ–—]oëSf{åZÕ$S6 !„P‡:‘ `óæÍË–- b³ÙK—.]¹r¥Aáææ¶nݺõë×/]ºt̘1`òäÉ'OžüôÓO%‰½½ý´iÓŽ?ÞÖãNNN7n܈߸q£H$b±X¯¼òJë §µgÏž>ø`íÚµÅÅÅvvv!!!Ó§Oo§…ëׯ‰‰ihhX´hQ‹KS§N¥ØlöСC9ÒþÀJ¤“6v¹úÝ1­F­¾­P„p8œNu¸’sùJÎe°çÚ C‚=C‚…!¶Â.·ªRT$W__£nè ×ÜÃ2ßÇ*=§nˆiZ…BHÎ3 ýú ¥Úþ«u̯ªúÝboAÂà/gýº:Y Óh²”ÊýRé~™,€Í>æââØÆDu…<þŸÑ­/9ó]‚…ÁÁÂÐ aˆÀZ ÃúJ–¹K’öPj}îÖPŒ åQÕJGc7 ™'œŒž-d´ï‘¿„ÿv¹Àš$Ã8œ0Ç•ÉÜ\SóNUÕönÌ(¢•IÅgÒOŸI? î¶îAÂ`ah°0ØÁ Í?4òêê›oËK¯êÿ=Ðð\ùô¢’êÓ§Oµ³Ýe¯æèèèîîþôÓOãº÷!3‡ý…f¤—®_ؼ+ôêjCÊÞÚ¿íŠî%Á¡ÕІY¿ÊÕê!"Ÿ$óô[Â.äЭI…·R‹o×):žT>ÀÞ+XìälcÙ¯ç¸èùîX§äB^Ô›‰ýá/"‚ ¢¢¢žxâ £Ö"‹Í'd·ˆ±¿!3„ý…ȸ• oíÓy©ûsMÚaM’ÐØÉ_9/„Ìy!dŽZ£Î*ËL%%Þº[œÚ¨j¹0í~UÁýª‚ãwŽ’éí8(H" áÄã´9°µ¯"9vãv4;¡óÛN €¸¸8í)Qaá¡C‡˜,æÀ¯ÚÅqt6rK{†¼¢¬êöÍì]_žã º¾:¥(9¹ðVŠ(©°ºPçýʆ›7nÜ+o¤ûHz“oÇA˜Bõ Ì…ÈX>'t^O·ÂÔì¸vÿ<ñ_ƒ'@¹¬¶Â¦MV„!ö\ü+¡^¯±±qݺu_|ñ…F£ŽÁẪpŠÒTTˆ+*Ê333:ôÕW_ÍŸ?ßP…£> s!B=†ÂÛq·ã ÿ š¥¡4Ùe÷RDII¢[©Åwêõ:)ªÕˆNÞý‰ÂËa`08D:RlmamÚ¶#„ ã7Þøæ›o‚á9b­Û ¾—+ 4’òÄ¢´­ÒŠä 0ŒyóúÝÈo¤?̅ȼL˜0á÷ß/R©<˜¦ûá,R©`øðá&«±5’ ý\üý\üg‡ÎSiTYâ z“•´wå*yëû) ò+óò+óŽÝþ‘$ÈAN>ô&+#ÛͰ°Ìüú“â_ºNœúàì‰1;bòø@Q0hÁòŠÄ?1"(**–+‡©f°ø¦©ÑÊn(A0x<žiªC½QßÿÝ€zkkë]»vEFFî•Johˆ³µ°°0Æ;å"•êZccBMM¡JEÄ®]»¬­{ÓÔ +¶U„÷˜ï1 i”Ü%'‰n¥ˆ’ *óunÄ'WÉ“ o%ÞúߟÀes‡»† C|v“•3é§'yÚ€vÙø.h”ŠºÂüÜï¶eïþrð¢U5i)pï[ ¾è¾º¡žecgí;$åý×ãŸrý×&ÏD¿ž‘HÔ(Íç;…˜¬F–…#E©þùg“ÕˆzÌ…ÈìLš4éÌ™3111…"ÑŠŠ cW' wìØ1iÒ$cWd<ÖÖã|ŸçûTÕW¥ˆ’’ “’EIE5"÷×+ê¯çÿu=ÿ/à[ðG¸…x† C:zw“•‹Yç3Åé+ŸXe{ú‘,6ŸÏ˯¥¼óÚàE«&ÓÂÙÕëùôUÇ‚ É‘ÿþ¼êNbé…_KÎÿ¶ewÏ6õK¸³2#˜ ‘9ŠŒŒÌÎÎNHH¸víZ^^^vv¶Á«ðõõõööŽˆˆˆ‹‹ëK›Øsí'ú=9ÑïI(“Š“EÉÉ¢[)¢¤RI©Îû¥Ò?r¯ü‘{l-mƒ…!Áž¡AÂO;Ï®5`¨ëÐ×¾-•”~0åC –e—?ˆÁP”¬ ‡em!á÷íSÕÉøƒü@ÝØ ‘ËÕŠF‡àǬ}ü¯-š©ª“‘Lhr’Ýw~*tºüÂDKWQ[öÑ”KÒÖW&_×9禱¼ôÆ«óp:B}æBd¦8Î{ï½×Ó­èÝœù.“‡mXTaÕýdQRraRJQrmñ•ËÊÏfœ9›q\mÜè€$ qâ9µ_Q€`(IJ“)ÎXr0æÓéŸy9 4üçéH[=[Ž¡cCÇ4?úéÿ¹ƒ ã6¯aR[[{üøñ—^zÉÒÒ(=¯ÎJ?MçÂÒßÏ8…?Qrá}éÁÙ“¥—Î(ª+m‡Žô_ñ–¼²Œî/¤;‡½ýqîwÿ•WU¸?õÜÀ9¯£m½ Á´¬¼²ˆm?Üjð|’mÛÓÍéûDg,\ÇÌ.®ÕºiÓ&:ÿåååM:5##ƒ>ïèè¨!§Nòöö¦(ª®®.+++>>~éÒ¥'OžìZ“ÚG§ØS§NÕÖÖÚØØ£ -Ì…õ/ì½Ø{M1SCiò*rSDÉI…‰·‹o×Ée:)©}pªöÁ©´ŸÀÓÎ3ˆ~×ìlǵk}3ÃÚyÞ¯*€RIɲC‹7F}, 5ægê³ FFFÆ–-[^yåÃo-˜ðtê†7}¢W ñ•³þ¯¾­Í…ŽacÜž|F)“^‹™î=oq‹ÅWÏmøª¾¨à·±˜ €°ò_õÇ2Yö>+Ÿ9¼ÁÑ$GÇŸd( Gñ/ÿ²¼€ç;Ÿ`uzzµ››[óŽ=ÿ.´ÁÛÛ[û`hh¨@ ˆŠŠêB9¢(jÿþý“&M:þüñãÇ£££Q‹VÏ Gõ’ }œ|Ÿ~á“ç6ÿºüìÿæî^6öÕQ^£ÛXX]x"õøû¿¬vû”ßÍûâ÷Ï®æ\i±³3ý*™&“K×[u&ýW#~Œ¾‹$I(//ß²eËÝ»m¾äí2kߎ£sÙ_—ªS“¬x³íþÙq›aa)¾r®øÌqШZ®¦î¿l-“kŶuÐ(u,´Þ?Y¸Žc;Œ Tu²Ìâ_#%©›5òªžnTŸÅv eÚøIÿþZüëS²Ì”ªÁ€…×ÕÕEGG[YYÙÛÛ¿ýöÛô¾Õ²··W«›Ö”-++›3g޵µ5—Ë9sfÅà ”m'âàÁƒîîî{öìi]rRRÒ½{÷¾øâ OOÏà¶ s!B€$HAÀܰÿ3ã‹Ó+Îm›ýmLÄâ`a›ÉÖy?T^Eî)‡×\;í¿OÅìþúÊ—×ó¯Õ+ꇺ6¿S©V~t&~×_ÿÃi—EçBËå»wïþí·ß(JÇ"D]G‚'&—þ~ºäÂ/®§iOSMò;¯j” ·'ŸÑý½tþ}è«ô¥ª—eíŸzRrg“¦Ñè‹*ôOü€% QÔHî~&>ýT]ö÷”ZÇ–¡]›ŸŸŸœœ|îܹcÇŽmݺUŸ§Î;Go¦JQTTTTuuuzzzFF†H$Z¶lY;çi|ðÁÆÇߺä}ûö1bÈ!³gϾpáBi©îI„†‚ï‘B-1Iæ0·áÃ܆/xl¡B¥H+¹Ko²’Qš®Ò¨ZÜLh ©Égf‰3ÝÚÏ$™ì½ZÜCµû¯ƒgÊ>œg¢ÏÐ'hs!PuæÌ™âââyóæp½Ë¸'óîà8¹Ø ‘W–Ñ'•µÕõE÷GS××€F.'ûМ}ãá¸D°ƒ)ô—”ºQvoo]î!®÷ó<¿W–Ω¥,÷P~Ò¿ ’õ“mÜ¡fæŒ#òTV¥€¦±²öö'²¬Ý¼€%Ü3º3H¡P|÷ÝwW¯^õóó€wß}wÓ¦Mo¼ñFë;ËËËmmm5MEEʼn'6nÜxøða¸qãÆ7=<<`Ù²eK–,Q(ÉÉÉ:ÏÓ»¿ÆÅÅé|A¬R©:D7`öìÙ›6m:|øðÊ•+»ü;„¹!Ô6“MO:€eCjñz“•{â,z“+3â¼{C£Ø½¾Ì­¾«Ê­ÈÑY”s¨#Ç–­% pÚ¦^Œ–›AÞ½{—nèäÔÁ =±mí/Yöµ'šeP¶­½Sø‰«8„D8GL¸»iýˆw7¤º>?ôÕÊË ¸¤Ôòºì}õyG¸gðüb\A7«(/8”FU)úÕe‰6Ð3Oü€¥U¾ªýRÝ ®MþP–µ“?d9wÀ3@te/U‘HÔÐÐØôÒ#00033SçãÆ£lllBCCOœ8ñÔSO@zz:Ìž=›Éd€T*U*•m§G:FDDè¬åâÅ‹b±xüøñ¥¥¥`À€Ä\ˆ2 –,ËÑ^öz drÙ¢”$QRŠ()MZòÄϾۀÄVQæV/v¯»Õ7Xµì\´ñ±¾¤97†Ï….N$ìÔjµZ­Öh4ôÿÓZ«Õj…BÑúq±X¼eË–—^z)  ;ÍÐNÙ<ñ}`á$h:ICÞxWçýÿÜóè1¢qœc;…*Êoµ8O©åu9ëóŽrNçùÇ0¸]\ͤAš'«L%E©+ Nôó\háöËÖOY“Õü¤º®¸&q½,óü!+,…“¡“ ì7金¢ÚZ(*##C焺ÿoÛ¶mÎÎÿô;99µu¾ýöÐ3‘›§Æû÷ïçååy{{wøYºs!B¨+xÞ˜AcÇ  µÿWsÑõ€x{"X×°­kØ>é¶ µQˆÝêÅîõenuõ¼¦Œ(ÉE͹1ä8;°o§|SJ%ù‡v^dŠ=²×¬Y£ç,–îŽÕ†††;vL:u„ Æ[ÝЀV?ïh} š%RPëç9!IÝ E( €zøÿ (úàÑK”ö¸éNèJ M÷´UBÓ^¢ÞT‚¦Í¹8”FQ—ûC}þ1ËQü€–³¼õQ‘ÿ‡­*¼û™¬òN£´À‚ïÕÙB ”Aô1ÑêLûWµgë{[«3mUÔñm–žÏ´È…4•´ úÆ›²ÌoùC_³pÿ—þƒa=<<¸\nzzzPP¤¦¦Ò/”õååå‘‘‘úœoG}}ý±cÇvîܹpáBúLAAÁÀ<¸~ýúNµJ˜ BÝeci;}ÍòßËwfý£ùy~-›_Ëöɰ™µBì^/v«/s¯¯ã5^Ö\Eè~ob—_˜È±w’¤”J>7ÇcÊÌÖ·QjucY©¥«»º±¾äü/¦É…úkg"¤F£ùùçŸ‹ŠŠfÏžM÷C˜¹ÕÿçÒüŒÿ³Ž Ëêw{Re}þцû'd•#:÷ ¥®¸’Á´rñ')¿YSr¥âþIÀN¿Rd0J£hú§šA§2™emvÕµ•,»!ü¡¯Y¸ŽÓ狵`Á‚ØØØíÛ·K$’øøø+VtªR??¿Ù³g¿þúë$I>þøãõõõ7oÞœ1cF[ç­¬Ú|yròäI¥R9sæ?wyyy;öÀëÖ­3Ò¿ q>2BÈ0ÆÅ/`ûµÙÈ“°eØF\p{î;Ÿg÷ùŒºè,μ;$ˆK^üð‹Ç¾>þíCV½—÷ývuC}ë{äUå7ߘo¼6tS‡ d¤¤¤üç?ÿ1McºÃ°³¨ûŠÒP”ºSHÄ× bÏ©$ÃÂià ¨(8ÑÔß©7’²t1’²:½êeçÉËnèsÿæÍ›…BaPPГO>ùüóÏwa0ßž={-Z´víÚDDD|ÿý÷ôJmoËþýû£¢¢Z,dýâ‹/¦§§§¦¦v¶UzÂþB„a$—$‰Hz²HÈ­ëà/ž„œؼg[$)J7~Ãx})FÝØÀ°ä¶ØÆ#wï6HZ»Øû¥¥Puû¦YmãAQI’í¤C¡PcÊ&uEAoxãmi)œÌ²œŸ"èÄrtå?mÝ&0Ù6òú’Š$k§0ý !û[*|ˆ`Z­f¢øûû·Nf\.wïÞ½{÷¶·fûyŽÃá|üñÇü±žçÛ*íçŸn}rñâÅ‹we‚ž0"„ ¯"÷ãýï:±+\„¹|¢£þ!Ê’©|Úëâ§{ŒÛ,ŠRJk ~üŽë&dÛÚC«m<-X^‘øgȦoËKÁ,·ñh'¾ôÒK½â%2üçHùäÉOCÓ[K‚â矡(jÓ¦O  ˆ‡ÿOÒÂúàÑK„ö¸éNÐQÂÃK­K ÞTK»%ЀG/µ*¡é]BMÒ‡ÅçtÒÒ#’?d9Ózˆôÿª•Òêâs–ÖƒxÀ$ÙŽž)ÍÞWQðS§r¡JM _HW©”@©Ò¥¦( }Lµ:ÓþÕfgšÚ¿íá±>÷ë|PG±”Z®’æµÛ#MX¸ç,aÛ×ÿ»ÔŸa.Du‘Z®,¿[Pš’#JLÏ¿‘Y§ïKÊÑR1Õ‹â7ÐÜxu0,,mü‡¾O÷VÑÛx4”•@ÛxL¦±·ñ`0 ƒ$I’$[h¿¤ÏˆD"•ªå´n?~|TTT‹¹“ælËåžc‚šŸÙvbl;ñrÏ4È8TÒ‚Æ:çhîùC_eÙøv­äJÑoµÜiàtí G¯¥ÙûªDg¼‚ß%ú¥¡€ ™ÚЫûkS6¨$¹º¯¤¥û$^À–mW¶¹ë·0"„:AVR%NÉ'甦äT¤j”M‘…­÷`eµ­r¢XF4£¿ÚoáôÈZqô6OÏp{ò™û?~×úÓlã±ys'Ö\·n]‹3$INŸ>ýñÇ7h£aÈ2¾i5à°p›Àº¢›é¤¢à8ÞÙ\x瑟µª¾ºø¼ƒç´6žëËÔõêóŽê¸@0,=§ðý=ì—E€¹!ÔRU‘^XšœCgÁºÒê.EõsUJääëj½ÓŠ…a¶Ï2†=‚gþüùC† Ñ¿„Ë/LìÎ*ƒå¥7^gáäBQ”F.gòxƒæ/w~Œ.yôWû@{¥R1,-=¦Ìt‹|¶Ë5ö^*Ya}á©æg,\Çñ‡¾Æ²ëÄ/e…ÒŠdÓŠõè¦)j¥DÙXY^p¢æBiúvJóÈŸɲð Ï“çÙS­êí0"„Zª/¯§ä–&çˆSrËÓ Ôr½^ª²¸§áA>õåµ™?^myÕÊbkî©Ô:‘¾+wAëmöö t?"êƒ1f̘3fjê±RR[_tß!h48?Vðã^¥¤FV3òƒ-ô”m‚ÁÌÿaWá±ý0t͇<¯AÐ<ö?6xñêÖÅŽÿá‚F©¨+ÌÏýn[öî/Ím磣4ü€% +£¼â§—-t ûռÀ©…w6Õ×Þ««Î´²ëÖ–Ù½ˆ,{Èr+ßI¿§ÛÒ×`.Dfçüùó“'O¦(ʓɌ³µ°°ð`þµH¥ºÖؘPSS(Mž<ùìÙ³“&M2x-=N^['NÉ-Mɧä–ÝÉSÖ5êóƒÍt:À%ÈGìã4ÈÊ¥ÿp3K[ȸ üfà´Ùn™0aBxx¸ *j¾²îÀ|¡é¥$½²#ýb½üú•¬íŸ6–•rÝu ê'Ylþ ?Ÿ—_Kyçµ~— ÒH¡údШOÚºÊâ8Œz>ÍHU›-Ûàw›žD††¹™‰D²páBŠ¢ðù›Œ÷çރɜÅãý·¶²r¯Tºpá´´4kë–oE{JCÕä>(¥—’IΩÉ/Õ³SÐÊÙÖ%ÈÇ%ØÇ%hS ƒÝÅ¿ÜÈ®“íSÿ}Õe$.Ñ]…,k®Ç€ªÛ7G­L¾n;d$ËÚ–7зè—#^Ï/ (J]_Çäéîƒqzlœ,?;íÓwƒ?ÚÆäê@Q²‚–µŽ×†B£Á\ˆÌË–-[D"Q0‡“`ÌP¨E$88ÜU(’E¢-[¶¼ÿþûƯÓðÒ†²;y¥)9â䜲;yr‰Ž€[#™ Ç!ž.Aƒ\‚|\‚|øîÝo ¥Ö”Þºç<Üû©ÿ¾Ú©^FdT7^«=ýÏ®€×Öemß\px/ÓŠçÿê[0äõw2·mzpöÂ;pnŒsÄ„¶ŠòzáeY~væ×Ÿ®ù°E”F£n¨gò­/‰5Þgé‹p÷hdF0"óò×_ÀJ›ö†°`¥MtY]uï@Q5ùbñízYÁ꜔F¯_-–ÖG r È´4ðŽ#•™¢ÿ9~c4ƒÃ2lɨËZÏ­æyù„|òÈÜpKW ø­:o1;› Éaë>iQ²ùLßî]„B¡ßKÙPn²•AN›6Õd5¢^s!2/%%%0´[¾ÒÕÑU›-e½¼ìN½¬`ÙíÜÆ™>O‘ ÒÞÏC;RÐÚÓ¸+œYØóÿµy‘Q«ÐŸ¢¶:ëëmˆAÈÜxxx€²´±Q®VJ&™?QWý7Eid2½þö@ýæBd^RSSÀMÚAWGWmV$…eחΩÊ*Ò¨5?`aËsÙÔ)è<›Å5Ý*<„ D«®…©S§þòË/Æ«µyL&søðáŸ}öÙøñÿ¬¡Ÿ——·víÚK—.UUUñx<ŸÅ‹/]º´­«««?úè£ãÇ0™Ì„††îÚµ‹ÃáÔÖÖîÝ»wÏž=™™™”~kv诪 [ê3Ô UyZv¯‘º²½#ÛA°K° hí 7‚ìË‚íð_—¶é®‡—cè§ðñ'ÜK<öÙn†…eæ×ŸÿzÔe|ÓZå­/ ø¿ù-vøà\‘øgȦoéåútì â³ð5_=´á«ú¢‚;Æb.DÝ÷ùçŸs¹Ü/¾ø¢ðΦÂ;›8VBí&ËÝGQEƒ˜žòÌçó¿úê«yóæªpÔ'5õž:uÊÛÛ[{ÖÊÊè;VÑ5j4±Xüõ×_Ϙ1£¤¤„Íf€F£™Z×Òz_ú¼ÿ²µ“ɶuÐ(•¦ø´¨¯³°°øì³Ï–/_þïÿûÒ¥Kµriù-–ïèèäèè0vìØO>ùÄÞÞ#€Q¯Öô·¡···¿¿¿)+ÖÖ8dÈ›ÂÂB¸ÿ~vvvJJ O'NœØNQï¿ÿ¾ÝåË—µQlìØ±o¼ñF‹ÛÖ¬YÓµÖÆÇÇÏ;·u.Ô³êþ©ê^Ñío ]ù¬Ûh“þh™ J]‘^(NÉ¡G Ê´ù›G„§“K ÄÇ%ÈÇÞ×Àät!هЇЗñO¥}²Î}òt‚É´pvõz~}ƒc¡Q5å¶Ö—胮½= èIQý´¯‹Ï÷߉¤ººÚ€% ì§@úë`|!AX³fÍÆ£££ëêêV¬Xqäȇ³dÉ’7Ò[vqöìÙU«Vååå}øá‡óæÍ›6mZjjêôéÓ8ÀìhniUUAMËêÚÙÙ1Œ .DEEuø(Š:xðàîÝ»;ü¹oþ¹¬¬ìõ×_?uê”J¥zúé§¿ùæGGGúƒ$%%mß¾ýÀ–––_ýõ¬Y³è´Jï[ß|œ¢þU÷O/þëÎŽ~Ÿi« IDAT3'ç%¸ö7v:¼£P|/•^ol,T©(ÊŠ$] ?k$‡³ÜÚšmªI m,O+P5*ôyŠiÉv6P»×ˆ¥=n÷Ùò¿.Ù£÷ÛPTU°íÀ!$üþ±}ª:=EÝØ ‘ÖÒ÷·¾Ä°°l±ÃÉd€F!×ÖÒz_ÓRÔY[[÷—PïÕ”ØÊËËmmmµg›Jýàƒ6nÜHþ‹ÍÏÏONN–Édtÿ™¶o,..nݺu¥¥¥k×®=wîÜêÕ«ÅbqlllLLLdd¤Îº)Šjll¼{÷îš5kæÌ™cg×4xÜÖÖvݺuÏ=÷Ü3Ï<3wîÜ)S¦ðùmþ¦,))©¬¬ìÔVQEEEEÙÚÚ¦§§«ÕêçŸ~Ù²eGŽ4Í@ŒŽŽ ßx¹P£ÖTe‰SrJ“rÄ)9‘¾ëÓò=]è¥d‚}ü…$ÓdËx÷e×~ÏÛÿ?J£&H’ãà<äw€ëîéÿê[YÿÝD©Õ$‹í6FðÄSôý­/y=¿ åáO8?vkíâao}ÔT A´Þ!„ú¶¦\8nܸæg›¿^‰‹‹‹ŽŽ…BñÝwß]½zÕÏÏÞ}÷ÝM›6isallìܹsU*UllìüùóçÍ›G?xð@gÅÚãgŸ}vçÎͯ~øá‡¡¡¡[¶l™3gŽ¥¥eLL̆ t¦C©T ÚL©7nܸq#11ÑÃÖ-[¶dÉ…BAnœã6¶xªõ¾ ÚK-vA¡¾¡)fdd´5¾0""‚>‰D Ú>³ÀÀÀÌÌLím!!!@¿2n~Ü–+W®øúúÀÌ™3ÓÒÒZÏ‰ŽŠŠŠŠŠ*--=pàÀ¦M›îÞ½{á‚ vìØ±hQÓ† ÙÙÙ<ª««éÁúHOO€Ù³gÓ-”J¥J¥²¢¢ÂÍÍ .\H7†ÝÑ–]¨º¿ÑvjÏ6ÞU(vJ¥<’üI ¶úyÀdÆâu ¥¡ª³‹Å)¹¥ÉÙ¥)¹µbÐo\š•ÀNäC/+è8Ä“dõýe¡BõjøEE%Ô¢(ªu˜ÓŸ““ý¶úóÏ?5jÔ–-[ÞzKÇk@°zõê)S¦{xxÌ;wÚ´iôUGGG’$é™3gÎÔ³j:ðmÛ¶ÍÙùŸ=Áœœœ:û\]];[u?Ô¼ËPËPépŸT 1|~ëPØM I½øvÓâÒewò²}ž"YLÇ!ž‚‡#M³ùB4ŸœœyEÇѸ»v–¼¢ èx#„Ì\'~›zxxp¹Üôôô   HMM¥_(wSXXØ‚ 6lØ0þ|ú/•JÅ`0š‡Nú<L¹\.—Ëm^¬Y³ÞÿýÈÈÈæïy5 ´Ê²Ú ¼¼¼­:µžºH’dg«î‡Zwju?^kl€)þf̘¶þ¹?zôè°°°ØØØÀÀÀÆÆÆÄÄÄ={ö\»v­ùd-??¿Ù³g¿þúë$I>þøãõõõ7oÞœ1cF;«6:::&%% …BúÝqªÞîór‡ß‡iTäÃéY?]K™Ûñ#faù?‡ú|̺“ï«TàÃ2X»ôÖ®ï!¤C€§KÐ z¯¾Ž"è:³íâ2cw›Mœ81++ëþÑïÙ6¶ö#G™Ã·T^QVuûæý£ßÑþrc!3ѹ·o›7o^¶lYPP›Í^ºtéÊ•+ Ò77·uëÖ­_¿~éÒ¥cÆŒ“'O>yòä§Ÿ~*‘Hìíí§M›vüøñ¶wrrºqãF||üÆE"‹Å |å•WZd¸æöìÙóÁ¬]»¶¸¸ØÎÎ.$$dúôéí´pýúõ111 Ú¡]®é¤M‡zª¢ÀÊø]³–ö|ç‘MSFœ‡dZâÊD†a¶]\Æ`ìn3Ÿ¨¨¨“'OÒ+x›‚ ¢¢¢è¿BfŽ0ø¾pH'ýú IFÓQŠcÊaïöï7û—ghçm hçιööÀ[Pîå¥ÏýÂû÷)*ÏÓ“ßíhèTPÿMI0H{_w— : Ú pS-‚ØýzS\ ®g1ƒ`2ƒd0ƒ`2H&ƒ`2&I0™äËÑó5jUôü  Ð@þá`MùýA –™I—1ÐÝfÙ»¾zùòåFMHb±øôéÓEEEíìe2ŽŽŽîîîO?ýtëM`ÕªUÐÕÕÅBF‚$‘Yøç=òN¬çÉdÞS*3”ÊQZZÜsü0—`— —Þ,+ ƒ”Ù<=ÊåÔÒã>hÿWü¸9ñP ivÊmÄäy^>}Ùܺ¸ŒÁ4Ýf...ôÊb!ÔØ_hFJŽŽ¤4M;wqDÙŽúØxu5ï¿\š³»;Eýì1íñÕÕ×[ßpû§uÎ;¡µYHÏ7Ò³¿pueå÷RiŒµõÇÝÞô“î/Ä?Ý‘V ùæTA]£^[?Ó, Ù òv¹¸Ä|º¸Œ¡ýn³~ û 2CØ_ˆŒKÕ ¿³ãŒÎKÝ_§f.÷½TúTú‚•ÕHܰ§zY¿÷¢ßW'òDåz-ëÃÕ2 vq!„™ÀµTq¥í»ØbñBpíµ?.j\7—¶åpfóx Šú?±øÇº:U³Ž Y.½¢¢R­îN¨Sœl8ëçú= W÷­'™Á†Fc7 !„þ°¿QëÎBƒïƒ÷ Àa™lYyùzc›Í'I©F“¦P”«ÕÀ»¸Q¡i±™äÜ õªÔü–ÿhN@ð‰j“µ !„>0"#jÞYhðDHcÄ׎Ž/òxd²rùŸ Šâ‘¤‹5‡Ç›Íã92—‚ ¤JªøíVÙ•»r¥¦Û¬‰Jg¢Ðd­B!¤'Ì…ÈX´…FJ„Í…[X„[àôážTRÕøëMñõŒ*uGûÄp AHf¶B¡¹KÚ¾‹v>nOn]fÔDˆz\^IÝ©›âÛ¹5­ç•2H¢ELTÊëý¸é ÀAŸ!dŽ0"c±ì1rÑÓ=Ý d,Àß’_oŠ3EÒÖWíx¬È—¤ìêœuÍž¡®z?dá3¦k%B¡ÎÀ\ˆŒÅsü°žn2 EݺWóëMqaY}ë«{‹§Ã\Âì™ "ñÞ#3Kîþ¾÷þÝ‹˜ BÈLa.DéK©Òü™^u&Q\V#o}u €;e” ØÇV»e JýÏK䡸{Î|mšv"„êÌ…¡Ž5(Ô—îTœM*«­S¶¾:dê(A€'¿Åy•ºiV²£5ûÿÙ»ó¸¨Êýàß3 þ¯£‚  ¸"(h.I„ËK½®¹Dd.mJEYi7mÁ,l3oq©[¹µx3•4SoàŠ¦è .#²ƒ Ë0ÃÌœßc#²/sfü¼_½z gy¾ÏãŸsÎsž™äû’¶¥‡”Àä  %òõ¯§Š~;W¬P6|X„a($Àab˜G/wq“çêæ -¼eSül¬ðÝÀÜá;5˜—feeÝR«}ÆûÃyK­Ö•6ZÅ.¡¸By ³è•Ö©Îó øLD?ç ¡îîŽ-½~P£a‰h^¤¤§[ÓÁÌ r!˜OOϬ¬¬s*•1sá9•JWÚhÍœ¬XñKFAæ•;ÚF‹ZZðÇt‰ qs°¶ÚNFûð`בý¹é&r!˜—ðððƒ~RQ-çE%¢O**t¥RЬ]¹Uµ/£àÂ5yãÅ©íĂȡnr[¶õwÆ×ÃzÖXŸ—/_Þén' Á¼,_¾|óæÍ§e²„ÒÒuÎÎ<ŽËi‰JKO+•‰äAÎ+,ѹ«û2 ®Ö_nðo.vsh€³… }¿!OE÷ð™Öó€\æÅÎÎ.%%%**j[eå…"ÁÁ!ÂÒ’‹kÊ·Ôê´ÚÚÄ;wnªÕ 䤤ØÙÙ¼ŠùÓhÙôìòýy¥µ÷ú¸XMsÞבÇëH¼kð¬ Ûø(`N ÁìDFF8p ..î¦L¶¬¤„ër‰$99922’ëBæF¥Ö;_zðda©\Õx¯¿·Í¤0÷~ö˜îxp ‚9ŠŠŠ’J¥‰‰‰iii¹¹¹R©Ôà%üüü"""D¢–ªí~ªkÕ‡Ï:S\¥P7ØÅ ð³Ÿæàmc’¾€ !‚™‰D«V­2u/º›òʺƒ§ f•(ë.=Ãã1a}'†¹û¸X™¤o`rÈ…„ü²Úý™…^*«ÿn: oT°sô0w{ “ô Ìr!@7w­ ú—ŒÂÓ9w?õ!¶ä?<È5r¨›ß ¹ ûúëFå/—nV6Þå`#Œ q;ÐÅÒÂ8ËD@€\ÐÝhYö´ôξŒÂ…5÷º;Š&„ºGôsÆÊ‚Ðr!@÷¡Ö°iK÷g–+ïíé.žæ>4ÀÇ @ º…Jsô\Iêé¢;Uu÷õ°æÑ¿§­ñ;]r!@×&¯QÿzºèÈÙ⥦Á.†¡¡þÃ<|=Ä&ét-È…]UI…êÀÉÂÿ](U©.F(à3#‚œ&†º{8Yš¤oÐ!t=·Š¿df\.×j®=#òÆ ty4ÄÝÑVh’¾@×…\ЕHóªöežÏ­h´!ÙX êöð`kKü½€ŽÀÏ€.€%ÊÊ­Ø—Q˜“WÕx¯³Eô0÷‡8[xÆïtÈ…fM«eÓ/—ÿ’Q˜W¢h¼×ÛÙrB˜Çð@G>KÏ@g!˜)•Z{ü|éÁ“…%rUã½þ^ÖÃ<õ¶GCA.0;5µšÃg‹.ªT¨ìbˆ‚}í&…yôñ±1Iß C.0#åUu©§ f•Öª.FÈã1¡}&†yH\­LÒ7èö ÌBa¹rfaÚÅRµ¦á£ÆÞÈþÎÑ¡n®ö"“ô È…&v½°æ—Œ‚SÒ;l£µgÄ"þ¸A®„¸Ù‰ñW8‡6`¦”JebbbZZZnn®T*5xû~~~ "‘iæá.ݬܗQpñFeã]öÖ¨·±ƒ\¬,øÆï<˜ Á¥¦¦ÆÅÅÉd2îJH¥R©TzðàÁäääää䨨(îj5À²t:çξô‚ë…5÷º9ˆ&„ºGôsb1B0.äB0;‡ŠŽŽfY¶‡@ààaié#0üÔ[juZmmâ;7e²èèèÔÔÔÈÈHƒWi@­aO\*ÛŸYXPVÛxo7ñÄ0÷a}x Ÿ@.ó"—ËcccY–]`k»ÎÙ™»3`†Ít›WJK·UVÆÆÆ^¸pÁÎÎŽ£rµ*ÍѬÒÔS…åUu÷Jl'†¹÷ïe‡<&„\æ%))I&“ ‰¹ …z<¢Dgçó*Õi™,))iõêÕ/Q©P:]tølqMmÃ¥g†÷v˜æîçimðºí…\æåĉDô¼½½Ñž¶à=oo¿°¨HWÚ€Jåª' Ÿ/U©µ v øÌð@§‰aîžN–†- ÐaÈ…`^òóó‰h……1‹êÊéJD^‰â—ÌÂôìr­¶áÚ3"!oô—G‡¹9ÙuŒ­B.ó’••ED\Ktþšü—ô‚+yU÷:ÙZ<:Ìmô‘KÏ€ùêþ¹0??ÿµ×^Ûºu«©;Ý“VËf\)ÿ%£ðV±¢ñ^/gË ¡î#‚œø<}º‹‹ dz³³:tè¦M›Zh°¼¼üå—_ö÷÷–––}ûö;w®R©$¢ŠŠŠmÛ¶Qvv6cèeáô£àóù={ö|æ™g8]ŠÌŠJ­=r¶øÕ”¿¾Üw½q(ìíiýÜ¿5 úìïŒP]ÂÝùÂ}ûöùùùé·Z[s¾j†®¢V«-,,üüóϧNšŸŸoaaADZ­6:::$$ä§Ÿ~²··/,,LOO/--m®©²²²ððpGGÇÄÄÄ€€€ŠŠŠS§Níß¿_­V׿™««ë|бޮZµjÙ²eîîîM¤W¯^UUU/^ܰaCHHHzzº¯¯oÇ u'y¥µÞÎÝóaÛ¥æÈÙâ_OÉkÔ v1Dý{ÙM óè+±1Iß:ŒaY–a˜K—.¯êýår¹½½½T*õ÷÷'¢k×®ùùùUUUµ1ž>÷Üs™™™Gmò-·ÙÙÙAAA,Ûø1€Žw¸¹í555£FêÓ§Ïwß}×*ù{³Ú»‹‹{Æ8„½×™>·l“ÿ“úÏ‹s¶t¦©‡>¡ÿ||ÅŸúÏ2 ³®É§„{¶+!éæt‹{õêL—:Àõúu"jõÏIEuÝÁSEGÏ•(T #ä1̰>ÃÜ{¸‰9ê$§Z¹ ža˜o¿ýÖÛÛ[w^uuõÂ… ­­­œœ^{í5­V«?ì×_ ‹ÅëׯÏÏÏ  …3fÌP«N¨4VVVÆ0Œ³³³îKGGG>Ÿøðá¶ €eÙo¿ýöõ×_o2ÖWÿ:rQQÑìÙ³íììÄbñ´iÓJJJô9}úô¢E‹lll\]]wîÜIDº´´pá–KˆÅâÕ«WïÝ»·-£îöÆ v½]ªHÜyeÝNéeYOc„ëõëõÿó¹q#,/oqqñ!…¢Sÿh¤°\¹5õæËÿ¾p ³°A( xcº¼Ûoñd_„Bèºî^G...vppÐoõððÐ~ë­·Þyç1cÆQ||üµk×NŸ>]UU5gÎww÷_|QwXBBÂÊ•+ ^yå•_ýuÅŠ………ñññqqqQQQMÖfY¶¶¶öüùó/½ôÒìÙ³uÛV®\ùØcýßÿýßœ9s&NœhkkÛÜòóóKKKÃÃÃÛ>f–ecbb.^¼¨Ñhþñ,Y²d×®]º½ . Þ³gϾ}û^zé¥3fddd8;;§¥¥·Úø¨Q£ ÅíÛ·{ôèÑö.uK"!/z˜ûÎcyÙ²ÊlYe Ä¶½s‡m·ÀÖ–%ªcÙr­ö’Jµ§ºzOuõX+«dWW{^g¾QTóKFá©+w´f­Dü±]¢BÜì­…¬`rwsáèÑ£ëo­5-!!A7O¦R©¶oß~üøñ¾}ûÑ›o¾¹nÝ:}.ŒŸ3gŽZ­ŽŸ?þܹsuŸoß¾Ýdá   ýç)S¦lÞ¼¹þÞ·ß~{ذaIII³g϶²²Š‹‹[»vm“é°²²’ˆô™²-ÒÓÓÓÓÓ333}||ˆhÉ’%Ï<óŒJ¥ÒÝݘ˜È0Œ§§ç§Ÿ~JDNNNº-ÄS={{{"ª­­m{º±qƒ]œ,ÔÝ„Çi:\ÿ÷d3±DéµµKKJ~W(b‹Švyxt8^ºYùKFá_7äwÙ[ ê6n‹•ÈhofàÖÝ\ØÂý…º2™L¡PèçÌ‚ƒƒ³³³õ‡…„„‘@ hð¹9ÇŽ  ¢iÓ¦]¸p¡ñ“Â111111ß|óͺuëΟ?øða†a’““Ÿ~úiÝ1R©ÔÆÆ†ˆÊËË]\\Ú8æ‹/ѬY³t=¬¬¬¬««+))ñòò"¢ØØX]g,:ôʲ²2"ruuíÀ¹Ý~ÊP¿Ås‡ ÑKË=<ÆÜ¾}¬¶ö@MÍDqû®í²,¹zg_zᵂêÆ{ÝDÑÃÜGöw °!t+íX¿wÿõ8Ý+.ìêꪻZ½aư°°¤¤¤W_}µña+V¬˜8qbPPP^^žÏœ9sôËèè²qtt<444>>>88¸¶¶633sëÖ­iiiõ¦ÑëÛ·ï¬Y³^xá7jÔ¨šššŒŒŒ©S§¶°,Ž‹‹Ë©S§$‰î²u}¹¹¹D¤P(Ο?ÿÑGYXX¼ôÒK[ˆýðt«¿ÿ”°ü¿sGÚŲÝÇ[?¥ÃÂê}nKßZR/+u )îÒa€PHD…š† Ê´ A(dˆ÷¶ŸæÑÛ‹ó=L®}ïÁ[¿~ý’%K† baa±xñâçŸÞ ðòòZ¹rå믿¾xñâ‘#GzxxDGGïÝ»÷ƒ>ËåNNN“'Oþᇚ;ÝÕÕ5==}Íš5ï¼óŽL& …ÁÁÁO=õTã §·uëÖ·Þzë•W^ÉËËstt yüñÇ[èá믿§P(ô·6êMš4‰ˆx<žŸŸßìÙ³¬¬¬Úù ÷Ò¡Û´âñˆHÝ¡¥+ùÿ²DÒÆvž\J$ä=ìüh¨»³mG<èºÚ7_Àýuä„™kSZWG_Mn£˜pϨ71–ž€r¡‘¤Ämõ˜ü= {÷ 2ÑÏibXë§èÄy¡¼R¥ûühˆÛ̱>­ž²é‹öõ­}ÔJS2 ›|îD‡»çNRkjˆh¬e;.?áiðntÈ…À-eöÀÉÂ&wqºNMžZ½¹²Ò‚aæ4›)Ô‡\Ü:r¶¸Áâ…Äq"$¢L¥riq±\«]ãääÕâúê ‡™À¡Æ“…%—JK‰ˆ%ªÒj/¨TWêêøD¯;:>cggØBÝr!p¨þd!§s„Û*+uD ÓK ˆ³³{ÒÖ¶O{ž8äBàŠ~²ÓDØöm eÈ…À•#g‹½œ­–Læð>B0 äBàŠ·‹Ut¨»©{mÅ3u Ûà‹g>ºäB B.äB B.s3nÜ8"º¥nøŠNéÊ 8ИEÌ r!˜ ":§R³¨®œ§§§1‹˜äB0/áááDôIE…ÆX5DŸTTèK<° Á¼,_¾\"‘œV*JKµÜ—Ó%”–žV*%Éòå˹/`¾ Á¼ØÙÙ¥¤¤0 ³­²2ôÖ­UUÝkxK­ÞYUzëÖ¶ÊJ†aRRRìì°à"<Ðð¾0;‘‘‘ˆ‹‹»)“-+)ẜD"INNŽŒŒäº€™C.s%•JÓÒÒrss¥R©ÁKøùùEDD$$$ˆD"ƒ·Ðå ‚™‰D«V­2u/ ¸¿ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆˆ¦î)•ÊÄÄÄ´´´ÜÜ\©Tjðöüüü"""D"‘ÁÛ€n¹ÀôRSSãââd2w%¤R©T*=xð`rrrrrrTTwµ ‹B.0±C‡EGG³,ë&¡éñÔ/œ\¼ _¥$.ž Ý’L&‹ŽŽNMMŒŒ4|èÊp!€)ÉåòØØX–e#çÑÇÐè霄B"rñ¦ÑÓéã?(r±,+—Ë9©]r!€T@¬³ IDAT)%%%Éd2ÿ!»–îÿ:2<Š]KþCH&“%%%q^ºäBS:qâÅ,%ßHy|ŠYz¯4€r!€)åçç‘ß@£Õ•Ó•ÐC.0¥¬¬,"®î)lŽ®œ®4€r!!€r!!ŠZžcê.t r!€aÔæ/ý}¡ª8ÓÔè ¼À0¬{ϪºœRòûB‘k¨mÿe®¡\T™åsß—V¶äéK#&Ó¤EÄÇßfèü$0 F`eÓ7Vžµ^Yœ©ä8F>A,KjË(;“r³¨,Ÿ®á¢<@  F7e¨U–§é0îý{ŸÏýNï=AÇ¿G.€ÎÂý…£›2¬¿EYœYòûBNï;ì?’ˆHQÅQóðA.0$ëÞ³x"§9M‡·sˆˆ$} Þ0À]ù{³Ú:S÷ŒAß!Ã0DôÝ­¶ž¨{Ù«7iµT]A•eä7žXEýF´¯³|hÆX‡/“^±î=K`ëÛ¾“ ›Âs'& *%¼¿õ‰¿ªÛ{úí«÷>WWPî9 BBQûyj‚Sµôëjé×BÇþbßiV=&ò„¶ííI{ér0@}˜ž0È…]Ïw·ˆÕ’¢šn]¦#;èë5tl½ñÙ¹´µ…`_Ë`_KÝçºò¿*Êÿ’ŸK´ô‰÷š*r %Bzx!˜€þ:ò‰¿¶u¬†Gb[ê3Œú #'Ú“DÛÞ¢ç>këéÓ²o°…Õ(7þ«¸ñ_DÜkªU¯)|+÷Žõ­UIIIµ ]ËòåËMݸr¡a„6¬²\÷Ù.ø9› Åm<1þË å•*ÝçGCÜfŽõiùx"Úäÿ¤þóâœ-íìé}úèÞ­mÇWüÙ™¦º‡ªË[äYë›ÛËÅŠ†QóiO>ÜŽSÞû¶è´T±%q¦²ð±Úú»ÔU2ù…å}*r)öjé5Žá ;Ð+V£$†ax8L¹ÀXµ¢êrJ“»¸{ŠØŽˆH¥hÇ)ª:ö¿'äÎ}©©É¯¹þSÍõï5Õy÷Áj•Ç•Çy"G«žÿgÝkªÀ> ]½bx‚Ò£O9=ô/†ßÎ;ÀD  ©úêwº÷ÔÇé;ñˆèè."¢^ý;r._ìiÛo±mÐ"eqF͵ïkó±eý´Êòê+Û«¯l: °öf%™ÀmÚÔ4ï«Ì-ÿó%§ˆ Äð;Ò90.äBƒiÝÅÅ…ÇãÙÙÙ :tÓ¦M-4X^^þòË/ûûû KK˾}ûÎ;W©TQEEŶmÛˆ(;;›a˜Žº•XXX 8ðÇìX;¸Ž ÝËV]ÏÚÙ‘sHøï¿VWWÙöîKDšZ…V©Ô¨j‡Ž°óL{zšººŠ'‘V¥äYàÅb4-«åa• ºVšëëì××­[÷ÆoQnnî¤I“.]º¤ÛîââÒöFöíÛççç§Õj ?ÿüó©S§æçç[XX‘V«ŽŽ ùé§Ÿìíí ÓÓÓKKK›kª¬¬,<<ÜÑÑ1111  ¢¢âÔ©Sû÷ïW«Õõ_TèêêúÁt`¼D´jÕªeË–¹»»79^½zݹs'%%eîܹÅÅÅb±¸½í#@·•þìV«Õ(j¶v}ž‰'"±wÀg_½üÅ:V£á -œCGzGM9·öebY­Zå;3Vhç@,ëµZ=a„ýë_ºÉN†aN:µiÓ¦o¾ùÆÊÊêóÏ?Ÿ1c†.­-X°`ë֭͵_RR"šÌŽ­Â?€ÌŸÏ¿téRRRRaa¡¡Ú¬ºžsúµ¥'_Š;÷ϵŅD¤ÈÏ;÷ÏéÏÎÉxq~ñŸÇš=“aì‚ÔU•MîdµZeiqý%º°^Ãû ‘•ß|?õY)ÓwŸÙY«®5u§º!K¡ÕìaOÑÙéçw.}~×Ò3·Nw¾Ùøøøk×®>}ú×_ýþûï?ù䓿ŽdYV¡PdddÌŸ?öìÙŽŽŽºí+W®|ì±Ç¦L™²cÇŽÊʦÿðëäçç—––†‡‡·½‡,ËÆÄÄ”——_¼xñÒ¥K2™lÉ’%ú½ .¬ªªÚ³gÏìÙ³uó‹D”––öé§Ÿ6Ù F£ÉÎÎŽ‹‹{饗ìììÚÞ=Ì‚™R*•‰‰‰iii¹¹¹R©ÔàíøùùEDD$$$´úo;#xÐÆ m¤›Þ(..NJJš;wî€:Û"Ë^úôÝ^3º-Û»#'å“à„w.nxÛ-bœ$f&±ZMs'Ö–^ß¹Õ5|Lã—ê6Z²ô»EDTTYøñ‘¶ý™2#döユوl X%}gPý/ùBK›žN’hÏ> Þñ“Z7eX^SNDgd§ÏÈ:;w¨R©¶oß~üøñ¾}ûÑ›o¾¹nݺƗt‰((èÞ/þ”)S6oÞ\ïÛo¿=lذ¤¤¤Ù³g[YYÅÅÅ­]»ÖÖÖ¶q;ºÔ¨Ï”m‘žžžžžž™™éããCDK–,yæ™gT*•îîÆèèèÄÄD†a<==uAÐÉÉIW¢Éè2räÈ矾íݨó…`ŽRSSV¯^}ðàA.BI¥Òƒ®^½: 55•‹m÷ ÚNÙK©TnÙ²åàÁƒºkOV'¯¨¹uÃyÈp"r:¢ü¯3uò;U×s¼¢bˆaˆa¾àÚŽ”£3Ç9¾$óÝYGgŽ?:+2ýÙ¹¬ZÝgÑŠÆÍ6^¨Ûà50Ü÷Þww¾üßÓ“û×ÿ¾Ð…rë=ÓÍo†K¯Ç¬‚jîd˲>¼y.Ѱ%Ì–~ÊP¯“s‡2™L¡Pß}ëLpppvvv“G;v,??????""âÂ… o牉9räÈí۷׬Y³cÇŽ)S¦èþ&''ëŸÎÉɱ±±!¢òòvü©¸xñ"Íš5+00000ð7Þ¨««+))ÑíÕuF[uéÒ%FS\\¼bÅŠ &üç?ÿi{Oôˆ…@×rèСèèh–eÉÓƒžœOƒ‘››áËÑÙs´e»L&‹ŽŽNMMŒŒ4|•6Ð×MBÓã©_8¹pðbÞ’<ºx‚vH&/´KýÛ¡X–=pà@^^Þܹs >é[?núÎŒõ«û\[\@߬Yüç±Ë›>¨-*{÷h¢«/ tæçú<½Ü°Ý3­§G-N¿~BËjõ[ª•U_glÛuú»Ébf{Âݶ#7r5æò–þó‚ã—-*¹±·ç× Ò¸ù«?e¨×á¹Ã·²,ÛÜó[®®®D´aư°°¤¤¤W_}µña+V¬˜8qbPPP^^žÏœ9s&Ož¬Û«[ÈF÷ÐÉ´iÓÚØI]àÛ¸q£[½s®®®m<½1çââ2uêÔ>}ú„……=öØcº'fÚÑB‡kpA.—ÇÆÆ²,K1“é›íõ'¡ˆÜÜ(êúf;ÅLfY666V.—sR¨EúñFΣÿ ÑÓ9 …DäâM£§ÓÇPä<2áx¡½ø|~ƒ-çÏŸOJJ*..îXƒB;{±Oϲ³DTzúO‡~ƒ…v6¾·~ÞE,ËjµÍÝ>HD®#F{?úØ…ÞT×T7}D½%º“×€±}n¼]©Vî9³kÖæiï\{³ü¦a‹Ú» "M]3¿ÔÝQã)C½ÌúøøˆÅbÝ„eeeé.(· 44tÁ‚k×®½}û¶n‹Z­n0C¯{üY:Åb±ÇßÇ›1cÆêÕ«܆¨ÕjµZ-5%44”ˆŠ‹‹×#¶òxS[.øúú*ŠÜ—ŒùB0/III2™Œ‚éÅçÈÐË~6aèÅçHš#»”””´zõjÎ+ÞO7^ÿ!»–Œ°ãصtý圑p¼²cçÏo?ä(qéßÓ¥_Oû®Æø½ëÊ4F£Ñjµºÿë4þ¬ÑhT*UãÓ “’’æÍ›Wÿ¾¨¤?;Gÿy؇)AÏ­¼¼iýõÛÖ6ϾJDý^x#{ãºÛ©?ñ-žsâÜ"Æ5×T¯™OV]“fþ~ðKo7(Ñ`I ®±Äª5jV­ÑjÔZµZ«Vk5º-j­Fsw‹Z­U7:L·E£®¿Q£Vkëîÿ²~SšªÚJ†–šøy¬Öªùëç0v^ØÂ·> BžKDVöí^gä¡F¤f¨]s‡B¡pÁ‚ñññ›6m’ËåkÖ¬Y¶lY«%Þ}÷ÝÝ»w'$$|õÕWD”““3mÚ´Ù³g‡‡‡{xxÈåò 6Œ9²þâ8õ­Y³føðá¡¡¡ñññÁÁÁµµµ™™™[·nMKKspph||ß¾}gÍšõ /ðx¼Q£FÕÔÔdddL:µ…I>—S§NI$ÝeëúrssY–U©Tùùù[¶lñööîÑ£‰©ý–!‚y9qâÑœ™ÔÚjÃãÑœ™ôæ?ï–6.]ј¥Äk8+ÄŸb–ÒGO“Ç+= äâÍôõ»u_ZØX9JœûõpíßÓ9¨‡S€OؾÕÔUʯ}·Ù8@Û¾tYs3 …"99yÒ¤IãÆkauCKWÆëõØôòyÿ¾6Xyú YÓô£š Z`x¼+ß×}ÖooËúˆ éå}=§%–%­–´,±}fù1|fõϯ«æ6MSIN]ÿ0MsÏǘˆ–Õ¹òÛïWŽ ÷5@,STHs3WÓ¿ÐùÖº™¶§Ãõë×/Y²dÈ!‹/nË£^^^+W®|ýõ×/^;88|øá‡íꉫ«ë'Ÿ|Òäš8úNÖï­H$zï½÷Þ{ï½:Vÿø_|±É§ª;ùDšr!˜—¬¬,"âêžÂ渹Ý+m\º¢ÝSØ]9ƒ7|å,EY¥toÃiHmºäâÍ’‹7/ïù_¼÷–Xú*[ëjźZi]¬ìøVr°=ÑüöÇ–®DTq)ëÜÛñžã&ð­¾JYVœñâüμ„S-äB3gÎäåå½öÚkÆéO‡±Z–X¢n}ŸKï§G>3²÷C_ÎMéX µ•×ôŸ5*yuÙ§<>–ºa×¾† À03nÝSµwªdÇηt1T¡äW()ç…Ùö>tç×}³ñ `µZM­‚o%¾º·à÷ªòR‡þƒ—½zuÛF":õÊ"¿y‹‰¨ìlÆÕí_(ËJ¼}ÌwöS\w¬U,Ëòx¼Ò¡D"‰‹‹3f—:ˆ%VË2|ƒC†_Àgø|¾@ÀÓýÇ×mð|Þßoi¸‘¯Û"àÝw–€'àóøú-×JsÿýǦæ:ãíàýTø¢ñtòuyÃg\"V«QW×Tä_Ûsóܺ’ë?ŽMŠœÛÞÈñv¦¦õíÉÿl<Öì:GH„F€\Ãðý|ÙÞ'ÖËmÃÑLÝÃ’CÿÚÊmŸX¶®²âúîíb/‰…ƒ¹„Žôzäÿêª*Óâ÷›»¨÷‚¥%™„¬ûR· KáñCCÖ~Vsëú¹·ãÍ!Q ¹088xÞ¼y]à"2ÝÍðøB[[—!¶.C,¬Üó.n¼qæ}ÿ¦qóV[§øöä×MîB"4äB0¹¬Xvì¼ÈNÌðVÛâÍ.ž*º§¶WG^ÓÔvéÏÎ%"¾¥•}`pÿ—×èž’æ[ZûUQ”ODZu]ƒS—¼ÂÎÚº†» ˆÏçóù|ÇãñЩÛ"“ÉÔjuãFÆŒÓêû^͇ìðí¾“ï{€º0³˜ˆî3ÞD=j«¿òÏŸ–j°ÑÞÊá‰Ðyž.pu×ÝNÞÅwòç¨}sóùï/ŽDhdÈ…À•rižc€qï›3©m¼zêZÕíô˲cY7]¨¸VЖSXK~Ýd_­GûV[í€áŸýGwá½ÒZíé7žõ™0Õë‘ÿ»±{{ãSÝã{ß·~ýú¶¬¿^Çã=þøã£F2h§ Y_¥ß÷à‚µ…õŒY3CæX[pûg˜/´!"­æx#sãÉB$B“@.®Üø=ëø[_{~Š×ð@S÷Å´ñÞÉ-?ó÷¬üÌ+êÚ&ÖØköDuÕÔ!¬“%w}kA]EyÍ­.ÃGkjª‰H«T ¬mˆH«Rš¤?mÑ`FP$ÍŸ?¿_¿~¦êσæjINZîÝ÷Š¢ÇM{"l¾½UkÑ\Éõ‰HìЦU*»ºú“…H„&„\\ ~âásÉöÎMôÈyZº"¥Ÿ¡¬óTP@µJ²²"êÕƒûÒŒQÏ3ÎxgùÜ÷¥•-yúÒˆÉ4iñ¹e]2ïÄ%ÙѬ›ÇÎWÞ*iåh†¯\PWñéí_ßt 稇­²ppr ›¹|sH„[ĸóë^þñWÎCGœ|eÑ€Wß5U¯ZV?ÚÛÛ?ýôÓÞÞš™Ö­àÃüý&±zNŸ×–k‹ ÒŸkéêβ,«Vó­¬|&NóŠšÒ™Î˜¿¯3¶³Ä x‚‰Á“ŽxÊÕ¦ãï(kÕµSo«Ukê*9ŠÊ\"ò l¸L]÷£Ÿ,D"49äBàŠÀJ4(.úÏÄ·Ó³÷ÎÍæ*-i4ôéFúq/‘o/zh …TVNWséøtüšò$lvAQ2Òx‰ˆ(ò bYR«¨XFÙ™”›Eeù´p ¥ˆX¶ìJÞÍcçeÇÎ矔j뚸ÑM'x Œ`ßÃíà²Ïìuè÷òÞw«ŒuQ¬é¥g¦ß‹o6ØœðNƒSš\ÚTô¯Âóòòzúé§›|kB{éWðé€áŸ}£ûPv6ã¯õ«ºw.Ì»së÷+¿=õTÄ"oŸÖO蜢«÷žná ¬­xöYèäó×uMî‡sß÷röýçäwM¹8¤›BS”ʉˆ«´ôÙFúq/yzЯQÿû¯¬ÝΧô ¸Ñ IDAT´ò¢I2Æx‰ˆ(îý{ŸÏýNï=AÇ¿7p.TÉkn¥]¼y4KvüBuAÃ;Á°õqé1z€dÌ@ïð ¡XDDW~LkpŒÏ¨þn|®Êz•!{ù`ÐÍ-X°@$âꇪë9Wþõ‘¶N%´µë»4ˆMvnÏió*._ôfû!Y­VU^Zv.ÓiPGý1— ³·/øFâØî—‰µ×ð—Z?¨ûá>{Ø\S÷ˆ Sú)4ý§%iý°—ÄbJZOî ÷zyÒãFÉà|¼Mé?’ˆHQeˆ¶X¶äâÍ›GÏß<–UtæªVÓÒŠÊK ÏÐ>=Æ”<4ÀÁ¯áÌSÉ_7êé?yøÃÄu‰·á™!>Ÿ?räÈ©S§ðÑcÝ“Ú:cv&–½ô黽f,t>Z¶wGNÊ'þ±ÏßÒjÐ WH9:óîãÃÎ!áýW¼e¨.™§‡ûFšº _g?Swî·iàVý)4=ƒ¥¥}û‰ˆ¦Ni"š·ãmÊí""Iߎ·P[^uë¿tSƒŠ’V^áeïëÑct°dô@¯á}–Í.›Wré¦þ󀑯ÏaxÝúM\7n\x¸ïÈlð¤v¼¢æÖ ç!ÉÈyèˆë»ï>~+ù¿ÔèåËcvÖÖ©ªo^»º}£t˧æöæ@è äBàVã)4=¤¥³YDD£Fv®†Äíx‘]¦/V㙯´ïD1=-]N~üãÍcç‹Ï_ky­A¡Xä5"¨Ç˜’Ñì$m¸éžeK/Ɉˆ&lùÔ¡K'·¯sp?ƒ‡Âvh uxB ÛÞ}ýŸ|îÌÏ!t'È…@›üŸìÔùK;ÕT§ÒRA>‘DÒÞ¢Mú¢÷ÂÎþR´AÒáŠ1¤ÕRuU–‘ß@zs'õѾFÙõ™í~òÓŸZ8Æ©·dô€£x ë÷hÇ÷ŠÊۥʊj†Ïýöü ™cÚ×30¡½Ø§gÙÙ —°‡JOÿéÐopëç°lÕõ¡=÷½ãA.³ OK}¬<®(Ú´62Q­’ˆÈÊŠ»Žq¤ƒãÕŸ~õÞçê Ê=GCHØž.)ò›ÜnakåÑ_2f€ä¡`O§övL§ä¯›|‘02i±o-ì"&蹕—7­¿¾s›ÀÚ&ðÙW[86ýÙ9¬V«QÔlíú<o´>v!ãÆ;r䈪&ßBìi´¢ªš|"8p Ñ*B·„\]™HDJ%)d-6uWŒê»[ÄjIQM·.Ó‘ôõ:¶‹ÞøŽì\ÚÚBq¼¸®ÒUhKDÄ0.AÉè=Æ pâÏtöµ³•·Š'm‰÷ ëÄ=¢ª(¿üy―ï·~胤É%xlzù‡¼¿©åÃÌjùs¦{cuUÙ'#æÂª² Däéi¼ŠÐ-!‚YÐ_W´4Qч;ݸI×®QpκƉŽ·†Gb[ê3Œú #'Ú“DÛÞ¢ç®Ø’“Uמ›÷´.Z9ò=Åýç>Ìq»ZGÆ{d’Ûñ6ãè."¢^]ìZz§.M¸°î ±O/—a#]ÃLjœ]‰H~å¢lïw¡má[Zeþ~Þ/{ÜÇDéŽo¼«çôù7¼í1N3“ˆX­Æ¶wŸ’Ì?BÖ}Y[ü÷“@ͬö\xüеŸÕܺ~îíxäBhRddäâââd2ÙÕŒÞ.Òv‰$9992«pCg!‡Ož>!Å¿HZ-¥¢wާϾ >þdmMÕÕ”“KååÄ0ô´ñ~lc¼DD”ü*‘FC5$»rwië)϶ˆYs5Þ%lTyÖ©’ÌÿÝØ³½×Ì'½£¿sá ]ùwÕܺ¡QÔèsaã]uò;U×s¿•¤[¢á7ñͰ¹Õž—¼ÂÎÚº:cŒº¦¨¨(©Tš˜˜˜–––››+•J ^" ÀÏÏ/"""!!»w$¹8TòŒ«93¡V&Ф‰´ÿ¿@gÏQšÄb’øÐ„(Š~” \±yÆ/úúÞg+ê=ˆ&-¢° \”2_< ‘ó°çaîc½ðþJïèÇÀÒͳ×?èà‹,µê»¹­ñ.݇ŽÝQÊDDx ´F$­Z…w‚CW‚\\ÑOžq}•ˆhÐ4€ÃöÛÀ8ãýî­v=Å'~w*[‘ª¬ÄÂÑ™ˆœCÂo|ÿµººJ÷<ЦV¡­¬ÐßxßÒÊÆ7àÖÏ»zýc˲ššjž@HDZ•R_¥#«=teÈ…À• _ÿæèïõÈ'K¸M„fãA¯i¥ÉýÏ¿Y­†áñDÎný^|“ˆÄÞ=Ÿ}õòëX†'´pé1öQÝñwõúÇ‚~/¼‘½qÝíÔŸø–bß9qnác‡Ž8ùÊ¢¯¾{·L{V{è +N}|?ý]Ú|ÐÆkZýãÿÙäv—a#]†Ý÷¾lý2„wYyú YóIý-Á ï48«…Õž±È3t?/ª°cL|a×È´ñ@÷ƒ\ÐMøûû‘²¤ÈÔiH×%///SwZ\ÐM"*8šjêŽ4¤ë–\0È…`Jf;ÅÅÝ0uCæÂøñㆹ±ç«üC?›É/©²¤(ÿÐÏ7ö|Å0ÌøñãMÝhž;ó2nܸ#GŽPQ¹¹¯jQ 8Ðxÿ¦oI¹x¯hI‘‰ÆÛ˜~Š«ç´'LÝÎé¦ÍtCæ‚¿¿LLÌÞ½{u+x›†abbb¸ Ä`(È…`^,,,ˆˆ._1j.¼|…ˆ<= ÿöÒV鯛›eÔ\˜›Ed¢ñ66~üøËW®È~üÎÂÞÁip˜Èň¿ïF¤,)*;›a„i³±cÇíß¿ÿÖ­[¥¥¥Üj#ooï &¸»»›º/Ð:äB0/ááá¤ovÐÈâå>­–¾Ù¡+mŒr÷ÓwïFE<~ëÇwžVC{7Þ-mŒzÍS“E%ë(ôë7ïŸýç­ æ6ÅÅãL›¹»»/\¸ÓÐ]áþB0/Ë—/—H$t)›6|JzGYû°,mø”.eK$’åË—s^®ÝxsÎPÊÄj9/Çj)å Ê9C¦/1Œ“WŸ"¶GŽvÈEÍ™¶oëâ.®yùå— äììl‚.…³³ó AƒÆŽkê¾4 ó…`^ìììRRR¢¢¢Ø½?SæIzr> ÄÉ5å¢":{޶l§ü†aRRRLò°¤~¼‡¾b³~§éñÔ/œ“kÊ%ytñíþŠddüñªÔÚK7+Ï]­˜ñÆ/Öön÷'`'¦ÐS\f¹ÌNddäâââd2½»Žër‰$99922’ëBÍ©?Þ/r^Θã-¯¬;w­âÜÕŠK7+Uj-YÛ7ŒøVL•%Sm„Î@« ÁEEEI¥ÒÄÄÄ´´´ÜÜ\©Tjð~~~ "‘Èàí·Kw/ËÒµ‚ês¹çr+dEŠVopd ¹ë ´ r!˜)‘H´jÕ*S÷ÂxºúxY¢ÓÒ;g¯VœË­¨R¨ÛxC¬SÌiÇ íðÜ Cäçiíåli'nÇ¿6m™r©¸ë´ æ À0m„BÝ'„º_+¨I»Xšž]ÞêÄ!."˜äB00_±¯‡x柬kGÎÿu£²ÉÃø¤¶cL¿ð2èá:2pBÀgÜD·Jj›;À)fˆû5 Í0_œ¸š_½áû«ÕµÍ^JÆEdsƒùB0¼‹7*×ï’Ö…îŽ÷-Ž#"…˜‘½_ÐäB0°39w6ü£¬»wø‘¡nÓGß÷G& Ì®#€!¥],K9xC«½· õcž1ážÊ:­€Ï¨5w·ã"2€Â|!Ìá3Å›÷_ׇB†hö8Ÿ˜pO" y}}luÛm˜;BRš¬—Р̀aü÷Ï‚þ¸­ÿ’ÇcžŒê1²¿³~ËàÞöÝÑþo>Ê9µÏ]€a¾:‹%úî÷[õC¡€Ï,™ì[?Ñ ?{"ªSÖܸpÄØ]€6À|!tŠ–e·¦Þüß…{+T‹„¼g§ôîßÓ¶Á‘.öÞΖ½<œ¿ª­6n M  ãÔöË_®¼rG¿ElÉ_þ¸o/ë&ègÜËÎX½€öA.€R©µŸý”{áú½eí­…ñÓü}\­š;edgOgK£ôÚ ¹:¢F©ÙðÃÕœ¼*ýg;‹—¦4X¿º/„B3†\í&¯Q´Gz³H¡ßâédùÒôG[¡ {„\íSZ©úpwNAY­~KO7ñŠéþ¶Vø~еáû8˜)¥R™˜˜˜–––››+•J Þ~@@€ŸŸ_DDDBB‚HÔÒ¥Oãè*ã-,W®ß%-­Té·ôñ¶yáñÞV"¾!º ¦„\æ(555..N&“qWB*•J¥Òƒ&'''''GEEqW«U]e¼7‹í‘ÊkÔú-|í–ÅøY°*@w€\fçСCÑÑÑ,Ë’§=9Ÿ"77×)*¢³çhËv™Lššiø*m ¯›„¦ÇS¿prñ6|•’<ºx‚vHoN^Õ†®Ö(5ú-a}ã&ôðCwLÿÊó"—ËcccY–¥˜ÉôÍvŠz„“PHDnnõ}³b&³,+—Ë[?ËÐôãœGÿA£§s ‰ÈÅ›FO§ÿ ÈyÔñ^¸._¿;§~(=ÀeÑ$„B€n¹ÌKRR’L&£ @zñ9b¸Ï C/>GA2™,))‰órèÆë?„b×Ãý_G†G±kɵk¼'¯ÜùäÇ«*µV¿%z˜û‚¨<#ü€!‚y9qâÑœ™Ä3ÖNæÌ¼WÚ¸tEc–ÏXmðø³ô^éVýïB馟¯©5¬~Ë´Q^3Æx#t?¸¿ÌK~~>Qß>F­Ú·Ï½ÒÆ¥+ê7ШEuåÚ2ÞÔSE;~¿¥„ Cs–<<Ø•ÃÎ€é ‚yÉÊÊ""®î)lŽ›Û½ÒÆ¥+ÊÑ=…ÍÑ•ku¼?üqû¿è¿äñ˜§¢{†9qÚ70!äBhˆ%úæ7Ùá3Åú-BoÉdßÁ½íMØ+àr!ÜG«eSÞH»X¦ßbiÁnŠ_P[ö Œ¹îQkØ/~¾v&çŽ~‹•`ùÔÞ¾Ö&ìžG®ä•Ö¶~P7Ò Æ«¬Ónø!§~(t°&Ì@(x@ WÎçV¬Û)½,«2uGŒ¤«·¦V³~—ôâJýW{Ñk³úx»X™°W`L¸Ž \7ØõÀÉÂÄW%¶SÂ=ûJl8)3ö‘û¾´° W ¤Èñ4<Ô+cÿÍ8ãåsß—V¶äéK#&Ó¤EÄïÄßæŠêºwçÜ*Qè·x;[ÆOp°v¼Qèj +"!/z˜ûÎcyÙ²ÊlY%·é0f2±,©Õ$—Óµëtè7:ô ¡·Þ n*6bÌñF>A,KjË(;“r³¨,Ÿ®é`k%rÕú]Ò¢;Jý_ñò©þ6Vøþð`Á÷}àn M^£&"nÓÒŠî}fY:ÞM¤“§hÕÛ´>‘xFš54ÚxãÞ¿÷ùÜïôÞtüûæÂü²Úõ»¥å•uú-Ûçó³´0Ö XÀlàþBàn ­þ–lYeâÎ+ÜÞ‡Ç04p%­'±˜NŸ¡´4® 5b’ñöID¤èPó7 kÞûîJýP8¸·ýò©½ LÈ…À­qƒ]íÄ §¥‘==hÚcDD¿þÆU‰¦¼·sˆˆ$};rîºÒ*…Zÿåˆ@§e1~B¾-< ð¸Õx Mót82‚ˆ(û2'7ÃÈã•]¦/V㙯tät…J£ÿ‡Ô‹P(ðX¸ÏÄ…d¶ñƾz=Jò¡;{uië{昶µ;Ì…$£ê“gòΙmþùꆭ-ºxcÂ=¸7]ýd©U?³7á‹kÛöNè~3î~Cµ#Ì…$ã䙼‰p篲4Ûtæï×—äh•ˆˆ`.$ùüv$«‹›ýSãä|ŽÐš´·ñQÛÃ\Hrñq·hO_Ñhoã%"¢¶GaéP›u“üÐHÚÛx‰ˆ¨ía.$""""€¹ˆˆˆˆ$Ì…DDDD0’µ=z4dfšµjf&€~ýú™µ(€Æ›]ïç”e!•³Èx‰ˆÈš1’u±µµ€3gÍZõÌYÞÞÞf- àŸñ¦$™µ¨TÎ"ã%""kÆ\HÖ%44Öo€Á`¦’Öo¸VÚ¼¤¢›W 7SEƒ›W^+MDDdÄ\HÖeþüù§Nã£EÙë‰">ZS§5Íüùóe/W‹4ÞäÈ{¢üIX4 îU$†¥ÆKDDÖŒ¹¬‹³³s\\œ Øü3¦NGü¯r=k˜™‰ø_1u:6ÿ,B\\œ³³ 4Ž7aæŽÀ®Mr=k˜†]›0wÖÁ‚ã%""kÆïÕ Ûºuktt´N§Ãâ¥r—Óh4±±±aaarªOõñ®œ'{9‹—ˆˆ¬s!Y£ððp­V»dÉ’ÄÄÄ””­VkòAAAÇ_°`Z­6yûMÒÞÆKDDÖ‰¹¬”Z­^¸p¡¥{a>ím¼DDd…ø|!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD*Kw€ˆ ¼¼|É’%‰‰‰)))Z­Öäí >|Á‚jµÚäíQÀ\HdyñññÑÑÑ:N¾Z­V«ÕnÛ¶-666666<<\¾ZDDÔJ1YXBBBDD„(Šž<ðz‡ÂÝÇôU²Ópr6}Nfú2DDÔšñùB"K*((ˆŠŠE1l–ïÆmÈ ¸ûà¶°|7¦AŨ¨¨‚‚Y*Q«Å\HdI111:.p¢Þ† ÿoGA¨·8:.&&FözDDÔª0YÒž={D΂Bi¦Š %"g]+MDDdÄ\HdIéééú™µ¨TN*MDDdÄ\HdIIII€\ÏÖG*'•&""2b.$""""€¹ˆˆˆˆ$Ì…DDDD0™JUA²¥»@DDÔ"Ì…D¦Q–þGÎÎYû-Ý""¢fâwðˆLñûä¢3qÙ;g¨=wè3ÛÖc°|µR’°c=NïC–奰s„«|‚н?Æ=•|•‰ˆ¨-ã|!‘i*{§žQʳögïœ!ÓÜ¡¾ q¯àå»ðƒ#0z2z CY öoÅ×Ôä5‰ˆ¨½à|!‘ÉHS††ò\åYûËe˜;\óâ×ÀÓsV GÈu‡2/âðvNQóq¾ÈdŒS†F¦;¼pñŸÃÞ ¯m¨ xúaìL¨í[^‡ˆˆÚ)æB"Srì>Y¡v­±ÓTépÇW0v&<4-i†ˆˆ¨nÌ…D¦T{ÊШåéðäÑìÞ5DEÑÒ} «.o¾ÅPžgé^9Ÿ;À×—uÕ#A(/ÅêS°ïÐÒLö…R"Ýv».··´-""j+8_HdƹÃÐ>ŽM¸ªìšpECG{çî~ºàèû ¦i‘ˆˆZ9æB¢VÃÖÊŠMÐÔÃa.‡¹(:ûyÎ*òMÐ(µrÌ…D öì>ês·QŸï9Ñ„”'½nrñtK«+ Â[3½Œ?–gìÉÞ>©*_ÛÒv‰ˆ¨•ãú…VÄÆ¥oùå?¤m·[W©½nmä…+:àìÕg÷ÔÃ冗¬ œiÜ~2yu{z[?fÜþãÙ¿ZÒTÛPtfuAÒ²ú޶dEÃàÁHÓbÏfôlÙzˆ…xï ±Ïûvq»ºÚaU‘.kÇC.CÞµóÓ¢¦‰ˆ¨5ã|!‘)‰U¥Egâê±ðäÊÜĹb•)ža$"¢Ö†÷‘‰L¦öd¡É¿ƒý züñ->yk^‡ÿMp耒B¤žD~S^lBk‚¦SÈë¶.½ò/ •Òβ¿wdmŸâ:â•“Ÿ©ºMDD­s!‘ÉTŸ,4y"”ØØbörÜ>;¿Æ™ý8™ˆªJØ;Á;#Ĩ‰pvor›Uι{æÊ®N6VœËÞ>Éeè2µ×ÓöŸˆˆ¬s!‘i' eJ„ÕõŠ^CMÙ ­û@1sŸ©Ì;!í1Täüù¤óMÏ:õœÙðµDDÔfðùB"Ó(>÷µsw“³«?nX’²)ç÷™†²l vŒˆˆdÂ\HdI£GfÖ¢R¹~ýú5â\¡CïY®¡ *G㮊ìÃY +sËÕ?""²æB"K²µµLð½ã&‘Êy{{7ò|;Ÿ1cÖWÿü‰¾4#{çôÒÔŸäèY s!‘%…††ؼ½™*ôؼòZéFR9ºÙPýó'¢¾cüоøRöŽ©.ƒÛùÞÑÀ…Åç6:Nnv]j«D‘a ²œ/$²¼ððp­V»hÑ¢±cÇÝø‚¦ ;vì¢E‹´Zmxxx [³qéí¶ÑÖ=ĸG¬*ÉÝ3¿ðÄŠzo‡‹†Âãù{Û¶°4ɇó…DVA­V/\¸ÐÒ½h…ÚÕmd\Á‘ÅÕ>‚"ž\UyåŒË÷§çW¦* ¿Ûí¥Øô˜˜3÷–¬SSr%"¹q¾ˆšIP¨:\Ø)ä AacÜYö÷oY;¦T¥Ö8¹"ç(€‰£:¹9+ÍÚK""j4æB"j‡€ÝF®Vع÷T¤d'L*¿ügõÓ*rް³ w5w‰ˆ¨q˜ ‰¨¥lÝx„m´qíkÜc¨,Ìùó©¢3qÆw+r®.Þ=#ÂU)TY —DDt#Ì…DdJûÎî£ÖÚwm—h(Hú oï ¢¾ÌPYTU˜"ívsVvshÌ¢6DDdnÌ…Dd‚Rí2低7/€pí ÂÒ‹ÿËÞñpyúÎêï)÷t:&p-C""ëÃ\HD¦äØcºÛ­ÿVØv4rêÊÁ7ªŸã¤Êïb_óÅ""²8æB"21uçP°6¯-Ä(V•Ö8'Ø)ɼ""¢c.$"ÓS:úºß¾ÞΧޯª¸Ùf¸Ùf˜³KDDtCÌ…D$ CyžÒÞ³úÒ†5pʈÈÚð{'Ddb•¹Ç‹Î®.½_ï7ñ]ìSTùEU8‡ˆˆÌ‰¹ˆLE,KßUt&®"ë@cÎ öt:vðÊ-rw‹ˆˆ‰¹ˆL@¬*ÉÝ=§¤‡Ã­ýÝÕŠ2é,µ¢¬›ƒ61ÅuË–-iiiÙÙÙí´\ÜÝÝ}||î¼óÎÎ;[º/DDõb.$"slœÔžÃ>þ.@LÌ|'U¾›m¦ô?aßûKê mùËxÙÙÙÙÙÙIII‘‘‘£F’µVFFÆ–-[.]º”““#k¡Æ` &j]˜ ‰ÈŠª:UuL- JNN^õÙJ¥ªûô9®ý‡¨Ý=-Ý5Y”ggæÙ§[±yóf__ßÀÀ@™ íܹsóæÍ¢h-!Ûœ˜ˆZ޹¬Tyyù’%KSRR´Z­ÉÛ >|ø‚ ÔjµÉÛoªö6^£íÛ·ë ¢æž‡½ÃÆYº/2R»{z‡«È¿raãêíÛ·Ë” “““7oÞ …²GÔÓV²Íˆ‰È$˜ ÉÅÇÇGGGët:ùJhµZ­V»mÛ¶ØØØØØØððpùjÝP{ou¼FZKdå52üÂÆÕÒå°}ûvQ»Ý?ÍzB¶y1™ s!Y„„„ˆˆQáí…™ÓÑÿfxÊ0í‘™‰#G±z­N§‹ˆˆˆ «÷c¾²2Ž×SƒžCïP¸û˜¾JvNîÁ¦`ññÖð÷ß°†™-3†) YUUU°Ê-w &"Sá÷‘ɺDEE‰¢ˆÈqX¿áwÈ xz"ü¬_‹Èq¢(FEEYä?ZÆñ†MÃòݸíYB!wÜö–ïFØ4Xp¼$«äädXeÈ–;‘©0’u‰‰‰ÑétèŒyOCd¯'˜÷4zëtº˜˜ÙËÕ"7p¢Þ† ÿoGA¨·8–/Y3æB².{ö쀩“ 0׿œ ¦NºVÚ¼¤¢‘³ Pš©¢B‰ÈY×J1’uIOO€ž=ÌZµgk¥ÍK*ÐϬE¥r/Y3¾wBÖ%)) €\ÏÖÇÓóZió’ŠÊôLa}¤r/QûÑnŸ¢V¹ˆˆÈÄÚóâSÔª1™’qñ)µ£¯oŸ9ΞCl¼M^¥¢$½ sߥŸXÛâSÔª1QÛôû¤1vEQ«ª”öö¾wÝß%üžÆ\(êõe™—í½Í{wŸÚ ãâSžÝ'ù\(ßB¶ÞîÝîqï:þü¡73ÏmˆŠŠ:~ü¸³³³Lå¨à{'$—ó9)–î‚Yµ·ñ¶ C?Y?ìÓ¯BÿýMàŒ9çÖ~ÖÈ«Ês³öÍ›.kǨ “Ÿrrí×màkæY}ªÛÀל\ûqñ)2 æB’Ë_ç÷<óͬ×Yº#fÒÞÆÛZˆCyNVîÑý®7‘ö¤mýáà‚'.xâøû¯U•Cµÿ÷ñ¾yÓü+úܺϜ[³ÀÁ·d¿©Õ’V€òŽ3­>%Jïàhpñ)2ÞG&¹L¸ù¾¯|ñÌÆY4g†Fð(K™Qw\÷££||0j$&Þ•Yÿõ6Óx)Iر§÷!K‡òRØ9ÂÕ >AèÞ㞀ÊF¾Ê­Ìï“ÆHn!¡}ž}@ÁÙ“ºÍ_þpµÒÎþô§ï¥ýï[ï1wÿÿãˆÿûAåÔ¢ û#³²÷ïYú öœZ/i('×¾æ,*•ãâSÔrÌ…$;û)ƒ^¹kÅaÝ¡Ã:™ÓRä8ˆ"*+‘~ÇŽã¬ÙÙxf¶,µêažñê«°æuįMO Ž€W²zû·bÿVÜ1¹ðš‘¶*+Š/ž?·v¥võŠÍ¿rü0€³ÿPr)U_ZbÓÑÅ9¨÷á×çzë}û]*§–î5µnÒ Pr¼hÒ©Ÿ¢–c.$IShy%yäM‡Ïν¶½o?^x¿&˜9Â,ã]óâ×ÀÓsV GÈu‡2/âðv ‡Â’Š[Kö …m‡î=g>}øÕ§{<6_P©ì<½»=øˆtT©¶Šþ‹>Ê=ºÿòöÿ¥'ü<8fµe;LDdA|¾d$M¡UßsXw虳ä}oÀ(.‘«ýúÉ=Þ Çÿ9ìðÚ†š¡€§ÆÎ„Ú¾åuš¯¼ªüí-‹ŠÊ‹,Ù‰ÚD±èB²sGn!¡E’«Š‹ì½|ì½|”ö†òòª’"·Ãz<ñliÆßUÅE • CE¹¥ûMDmGzzúŒ3,Ý‹c.$yM¸ù>—;åM‡/€7ӷܲŽwÇW0v&<4-iFF..™E3×=|äÒaK÷öΙú׬ɻ£îIýî‹O<ÀÁÇ/x΋g>[ºþŒƒ/<®ûi£¾¬ôè›Ïx>úðÂgü'EÙ8w²íäê6pØëx濫¢BÅf_^–uÙøeKZØ;gê_³§$Fß·oÞôœCI‡~Ÿ4¦,ërõö<ñà¾yÓÿŽÿ±%‰éá‡êòöÛo7²…êWÙØØ„„„üþûïÕOHIIyàÜÝÝ …³³óÀW­ZÕ@ƒyyyÿú׿U*•]Ïž=zè¡òòrùùùkÖ¬púôiAš;èæ”nÞG&yŸº«}H–;­ç/`É2(DÏ4MƒM$ëxOî€Á-주FŽþè·æ~3{Ê ‡þ˜Òb7¶GnØ^ç~÷A#ܨ¾gÐûÿ½î Aè»àù:Ö$ùùùßÿý´iÓìí-9<ô“õ Šé¿m9ûŸCWm¬û ÷ȾË6r©H+w>þ`·1%'P¬ÔÒ¥K_}õU)))wß}÷©S§¤ýîîîoä—_~ 0 Ÿ~úé}÷Ý—žžnkk À`0DDD„„„üøã;vÌÈÈØ»woNNN}Måææ†††º¸¸,Y²$(((??ÿàÁƒ[¶l©ªªªþ¡B÷ß¿yC^¸páìÙ³;wîܼÒÁ\H¦të‡Ãšz‰iÒá´(ˆ!?={ fnî×Ô6nù`h3úßT-o–º˜¦'} ~ìË™W¿®.]5®]ý\ü|]4v*»6{[ÐÈå¿}h _î_{àâ¾…w.òsíj’·OJ¥òÔ©S111>úhíÿ4OÑ…ä³ÿþÐPYaÓÁ¹ç¬vKÓÓÎþ烲¬Ë‚Jå?9ÚcØmu_)ÎA½ªŠ ë<( y9Õ—jíôUëÇ,™ÙcÂÓ¡ÌÎýo¿ßÈ›l›ðGP—.]ºtébü188¸u¤ {÷îÒ±cÇ‹/HMMÕjµ‡vttзoß1cš}ýõ×]\\~ÿýwc»õÖ[çÍ›Wã477·çŸ¾]ðÖ[oM:µö,Ýü¬‚ñNkÇîÍZ¬_§Ã¥4äç@aNŸEE…i{hZÍoy)Ø9š¦üOgœúõÔ¶ØÄÿ¼þó+3×M ÿxôÿ½çÙoŸ‰Ù±ì»#›ö§î½\pÙ šÔ¬‡“goï>Òö™ŒÓ~ñÈG¿Ñü;¡íœB¡••sìØ1´(ЧV,ÖÜ;yвX×C“ã>pò£7]ûºâË!1kܯﲬË6~î:²öÁß'Ù5县fM.ËHï=¡ úiºß9Xik³óŸ á/ý!QÔ7í÷5‰ƒ‡óºÏXþCEa©I,..ž1c†£££««ëK/½d0Üø_nn® nnnÒ...J¥rûöºï<Ô ŠâW_}õÊ+¯Üp~®ú}äÌÌÌ)S¦8;;;88ÜÿýÙÙÙÒ~A:ôøã;99yxxlܸ€”V{õêUã9ÅÆ—n ÎR›°óWD”–àülÙ†Ïþmñø`)\:Yºg¦dk‡Š2”þÅK©¨T*‡š¿ýEˆ……ûS÷wÚ©ì|]4~.~¾.~]]»ú¹tÕ¸hÕN 4>*hô‰ôãÒvYUÙÛ—î9¿{Aø+®®-íwû#åBååå«W¯;vlxxxKNª,È/¹”ê6`(·Ã.lZSYp¥èBrÿ7b ¥êü†¸‹ß}  Ïóo:uëŽê+AÖãñgk7[{I f÷ÐzJEÈìñÛŸûO~jæŽçÿ{håOƒž¹·û]C…é#ïÁ=Ý‚5VüxlmBÿÇï¼iz˜Ê¾E)ç¹çž;þü¡C‡ŠŠŠ¤9¶úæÏDQ,++;vìØóÏ??eÊ—«ÏˆwêÔéå—_¾÷Þ{Ç?uêԻC‡zÿðMOOÏÉÉ m|EQŒŒŒìÔ©ÓÉ“'õzýƒ>øÔSO}óÍ7ÒÑ3fôíÛ÷Ûo¿ýå—_žþù‰'îÛ·ÏÍÍ-11±oßëVÇlFé0’U0ÞW]1±±+«I!ÀÑ}û o¸»aÍøô3¼ú’I»i2ͯ‡iZ\<žƒ[ÚÏÆÞ¬)«*KÎÒ&gi«ïtst׸hü\ºú¹võsõóséêåì­T\ýºÃmA£>½þ ËÄ”Ý3Ö>ôbø«-íwûcÌ…DQܺukZZÚC=d’‰êª¿Ýâ?)ÊR”´]–uÿ<¬™õ×®3«Þ/˼ìàãWGW¯_ȴݳ”ÀqC¬ø1ÿB€+)—æ­:øéOƒž¹'`ì ¦Ãâ¼™)ßf(/N3èË”*ûÎöÎÝ\oòî9SP´—%ICæDþSG+ÕÍ~EEÅÚµkÿøãž={xíµ×–.]Zg.ìÕ«—qûž{îù¿ÿû¿êGß|óÍAƒÅÄÄL™2ÅÞÞ>::úí·ß®30fÊÆØ»wïÞ½{÷ïßïëë à©§žzâ‰'***¤§#""–,Y"‚··÷Š+¸ººJ%jt ¥À\H¦ôdzÕÞùÕ/ë|C"ËŠ†÷FbÍØSGgðçs{[òâ§‘|ã Œ4-öl6A.,¸P´oÑ¡¿Nü¥Ë½˜š{A—§»˜—šžÿw#ïçgçgWéØFiÓ¥£ŸkW???×®¾.šKyºê—ä•ä½øÃóÝïïvþ§‹-í}{¢TÖü–Ú±cÇ¤Ç =<<šÑ sGß®¹Gö¹¹5çÐ_z÷·qîäätéçoº=øˆ(Šú’âú÷öv[Ñyíñ÷_¸x¥Ê¡®ª- Ô6JÅÀYã~{áZVÈÓ¦ýúôJ·`Í gîõ¿cZöb©(êS¿“‘üûŽA®¾w Ûʲì’+gòÒòÒ:NQ¶›\è{KÏ~™I)Js ßùêhìÖ³Ç÷zðV…MÓâŠN§+--5ΫõíÛ÷ôéÓuž¹k×®   ÷ßÿñãÇkOÆGFFFFF^¾|yýúõK—.=vìØöíÛAˆ}ì±Ç¤s´Z­““€¼¼¼Æ¿õròäI“'OV©T +++³³³¥‡&£¢¢¤ÎH1±Í(ÝæB’WYeéW¾¨óŒ_@qt€r úè£!C†ÄÄļøâ‹µOóòòzöÙgïºë®^½z¥¥¥ùúúN:uܸqÒQi!éÍûï¿¿‘”ßÊ•+===«÷§‘—y{{7µt˜ I^ßýNúþGu²Axk<v—«ýúÉ:Þ 9¿oÄ;“1ó„އòŸßÁ¢ˆsG±ý Ly ÎnÍlßFiÓÍÍ¿››õù¥W.æ]Ôå]¼˜›z1ïâÅÜÔ¿óÓ*õ•Í…½§ýNCBoá¦B°+zN«²°àü×ÿgž ÑƦîXPZZ{÷Ýw=ºÇ í<¼j¯×ãÔ-0ä½ëÖ`³÷öðÖÇiAP(nzù=iÛ¸¿¾%j¸ËåfÕþ ¸š¢ÜÑ©¯1)n›  (‚B…  …  @þÙP\=|ý~APÆýW÷‚ PRÃW7„U?­V 5~ìóðí{ÞÝP{DÙ'/ny|¹g?ÿAs'ø¼©1¿ÕçÊH^¯T9öõ¹ÚѧÆQµ£¦sàCMm³µëvûÍnÁšœÓ×Ým(¼”ýÛ‚ÿ;´ê—Ásû|§¯¯¯ƒƒÃÉ“'  ))Iº¡Ü€Áƒ?òÈ#o¿ýöôéÓ¥»ªª*¥RYý÷—´_ ×}Þiâĉ¯¿þzxxxõû¼Òû.5rª±"€¬¬¬ðððŽÈ¨ö}-…BÑÔÒ `.$Õž<“+~¸ôzáÂ\ÔÀÔÉ&®r#foô{0èñÇ·øäi¬yþ7Á¡J ‘zùYL©ã/º-ÒѾÓMönêrm~RoÐ_.H—f/æ¦^ÌKÕåérгߦ†ãâÑËâ߃2. ôû¤1jWw(be%ͽS|ïªã/Ó¢^_–yÙÞÛG_V’žð³µ=×ÀK”ƒá§Ÿ~ºtéÒäÉ“ox§ÉŒsí/ì½\}Ï}nƒ$.þÚB=2̤óÿ{ôÃκž7ÁwDŸÆ_˜uþƒ® ›í?ÁÑ‚R!( ¥BP*… ( …BP)…ðÏNÅÕW·…R)üs¾âŸ®5¢TTß)(¯ž£P)¥kn+‚R©P^ýñúþ(ªëÛWÂõ‡zܺç=]í¡åŸ¿œ0oÕ¡•? žwß ïàÛØØ<òÈ#Ï=÷ܪU« Þzë­Ù³oüeÔÅ‹oÚ´iÁ‚ëÖ­œœ|ÿý÷O™2%44ÔËË«  à£>1bDõÅqª{ë­·†:xðàçž{®oß¾eeeû÷ïÿüóÏ;uªã%Èž={Nž|Cý¯­]\^$=¤˜š›z2ýØÁ‹o¸6M6² Û<ºeªwØêÿær;/ù§’޾ùœ÷è;•ö5?ß\ž›µoÞôFÎx™ß ×8|øpZZÚK/Yé+VÕYÕô°Ée>÷ó#˼õhü%Yû¸ú´èƒ45ªô¨Ò›°Ak“{6mÛ¬}» ž7ÁoTCÏÓ,[¶ì©§ž0`€­­í“O>ùÌ3Ïܰñ.]º¼üò˯¼òÊ“O>9bÄ//¯ˆˆˆÍ›7¿ÿþû®®®ãÆûþûïë»ÜÃÃcïÞ½o½õÖ;ï¼£Óélllúöíûè£ÖÈpÕ}þùço¼ñÆ /¼––æââ2a„zøÊ+¯DGG—––mlvéú0’\Œ“gò&¿ÊÒlÓ™i¼€^CÑk¨|Í7‡£Ú)Ø«W°W¯ÒÊÒ™ë¦5fÁÂNpñ|÷¦0C÷œüƒDƒA_Vª´wø;~óå[+òr:õé<ûÅskV8øÂãÓž{dß¹µŸ•çfûŒ½×Ê£fè[ÃDQT( ¤CFmÎ.5OÛ…F Û&üWµ¼è»þ7<“jÈ:~áÑ1^Ï¿Ï'´Wpppí»«kÖ¬‘>=WŸÚW½üòË/¿ü²´Ý©S§>ø Ióððøøã?þ¸Ž§2Œ¬Þ[µZýî»ï¾ûî» t¬úùóæÍ«oµJ7 s!Éåû£ßusó_4îY’õhoã­Ïòß>L»r©ÞÃ" / ïv‹àë'%¦YöþŠbeaþ…Mkºhl;¹p<¢Ëã+‹ £'<ôx÷Gfeïß²ô?Ò‚,$ xû“’K޾ùœ5äB ä¾}ûN›6­UÜDÄ_òŽŒ  þ#'â·;Ï>û, ¢(D¢Áƒ(ŠEDˆƒh6¤=¢Q¼ú£(íEƒhÜu(Š¢ÃÕ†¯nˆÕN6üsR-÷ô†²œ‚†×+ÐÜÚ7dN¤WHÖ½ÐÈ_ƒ¾ €RUs›Iå V¨øyc.$¹ø»LÔŽšnoã­Ó.íÎ_ŽÿT{¿BPÜìÛTÐíSF=T‘_1#ÆLó[{ç<@igß1¸oŸ½%=¤´³ÏØõkif:CUÍh‚ŸzAP©l;¹*›ÿnÍ )•J¥R©P( Eí ãÒNWUUU»‘‘#GFFF6õ¡rKŸsŒúHõß}sÀ¦—Íý(pSí]¶éðª_ê>&~#û z:Òóæ&¡R¡´3èËôU%J›&ßì«Ïã§cE½A4 zƒ¨7ˆQÔ ƒX¥—®tôÚ9ƒ¡êŸ=zÃÕsŒ'üs¨úNQ/µ£ÿg§( †*}mƒþê×õçú¦ ÿôPÔ z½t¾¾¼2/ùï†R¸ t}sÈœñžýLôUPª†¹ä2Ìß4k¯·ím¼µee/ùõº»!6J›šQA·ßx['ûN*ò4g—†~ò¥ô|¡‘h0zuŽï÷u¹c|ꦵµ/T*rßó\¶lYãO6ÞÕ2R(&L¸ås?AÛ>•æ_›PÇAè6¦ÈœH¾Ýš×²Úѧ´à\IþÙî&»É P)¡ª¹æeëòÇëërµiuBÀØAgw Ö˜¹Wís!™€qñ¶·¤ÅÕ*õnÃFp«Sƒ_Ì3¿Êü¼’K©îCoÓ—0”—«*Ê-ݵzÕ˜T«ÕÓ§OïÝ»·¥úÓÞýï–Ê’ëþõ‚ÿ!!OG¶0tpXZp.W·Å„¹°µ+LË>µqWíý ¥"pü°Oséîmþ^µ+Ì…Dd›m<‘~lLÏ;FæjocoéÕͶ“«Gè¨ýóq î9|ô±¥¯ ]¾Îmà°/<~Ó‹‹-Ý»ºUÏ…;v|ì±Ç||Z´¬‰´‚ðÏ—T¼FÝÙõi½X/ÿ¾-mË÷•…ù¢^¯°µírG¤&rRKúcÍJ³ Ž±Ãø£ î2;Òµ‡ V–ñð¿?3囌sÜ»ÞãèÚ÷Æ´Wl6T^÷Ô„ÂFÕsÂðOÞíìçYßUdBÌ…DÔRÑ qñû߬_ŸH¶u/=#½ç½Vc_ßïÔ¸¤Îå -Åø)¼.]º<öØcM]¬NÆ|š*mË÷i[¿ïýÜN]»¨ÈË)ÏkÂÒ•­ÎáÿRUZ@P*ï:pöxΚ?A IDATW9¹ÝìÑmBÖ…ïOýÕmàkn~w ‚ñwX”{,óÜFM¿gmÔíåã@ù2Î~¿Ûø£ÊÎ6øÁ[û?~—“w{ù°Ì…d]FýÛo¿!3žfü«af&€~ýZüi¹¦“Æ›w“­k{cÙi€IÇ«|¼R>Ò|a¯^½yäµZ-S•¢ Égÿý¡¡²Â¦ƒsÏY qºÞ?-ÿÌñ›_ûçiHQLýþË^O¿$…B¶.n¶.ÍýÀŽÕ+ɺrò« ¥"èžÐ³ÆwìÖÙä%º zCõÙ©›Ïí}!õÈ»Ž.½•6ô•…%WNW–傦Ÿu-´.«Ë0è lÔ½§Ž¾ùѶó­íÖ‚¹¬ËÕ7Μ5k.t‰gÀƒ™ç¿-Ê>T¹O4T*UŽvÎþÝ&¸ûO°Q·ÙØ]Cž6-ù—½¶ìûNë7#ÜÎźMn?˜ ɺ„††nÛ¶ ë7`Äp˜gƒë7H¥ÍQîzÒx7¯Ä p˜ç¬AÍ+¯–6G=j±Ñ£G›üV7µ+ òK.¥º  Àmà° ›®.¬?±á¯µmCŸ»_©®ûûÔ¦ÕÁcPAf(dÍ’Öü:xÓÃl;XéÓÉíDëXøŠÚùóçk4œ:V ÁUdMCñÑ œ:­ÑhæÏ·Àýi¼É‡÷*Ä|ðÌDâ^EòaXj¼Ô –LðׇBÛN®6:^9~ØRÝ13ó„B’ܶhúÀÙã -޹¬‹³³s\\œ Øü3¦NGü¯Òæ—™‰ø_1u:6ÿ,B\\œ³³³,…doÂ:Ì]›®>ügrÙiص sG a,8^²N6Î|»æÙ çÐ_z÷¯ûÕÇ»²îï^š’ÅÇKÖHz=ýò™UË.l\£rt žób}'jÆOTÚ;$Ç­(ÏÍT*µ‹»ækÿZ 5s!Y£ððp­V»dÉ’ÄÄÄ””­VkòAAAÇ_°`|ïx6R{¯ÙTäçùtÉM/¿géŽX—:—àqêòÞªžAèrÇø.wŒ—©oDdYÌ…d¥ÔjõÂ… -Ý óioãm¡ÌÝ;R¿ûB_V*êõJ;»®÷Më|ÛµO3T”7þ.§¨×—e^¶÷ö)˺¼wÎCÖ³~!µ.ÒâS%é¶æ{å¿¢$]*m¶ŠÔV1QësúÓ÷¼µ¢C÷ž*ò󪊋ZÞfynÖ¾yÓGnØ®vó ý÷7-oÚ'iñ©¢Üã®fÌ…E¹Ç¥‰Z‚¹ˆZ%QõcY¶]l;ºHÛi[¸üÛjwÏàÙ×=$WãÊÁ±4=íì>(˺,¨Tþ“£3ÿLpð…Ǧ=™ôö¿¤ùÂ:W{¾é¥wÏ­ý¬<7Ûgì½þS5ç¨ÉúI‹O¥ŸŽuñ¹½Ú÷Kd$ŠúôÓ±àâSd |ý‡ˆZŸàY Ž/}õÈó/ý¼©<'KÚYpö¤nó×ý}²äß*Ç´ÿ}k<¿ÎC'?zÓµÿ¡+¾³Æ}ððî̲ô?ö^]®^&ЧV,ÖÜ;yвX×C“ã>–vgü‘0àíOú½üÞ¥_8­H5I‹Oå&]8ô–yVŸºpè­¢Ü$.>E&ÁùB"j}ä–¼¤ƒÙûÿLývm·I3}"&Hëêýo €’K©úÒ’Î#Ã¥ókª,¸Rt!¹ÿ1Ò}‚²Ž? ë[í9ø©•ʶ“›¡²Ò£¥VEZ|*<<<ó܆üË»}ûÌqö"dz†%é™û.ø¤¼øŸ"Sa.$¢VIa«v4ÜmÐðÎ#ÇïeŸˆ ‚JeçéÝíÁG¤”j;CÕÕÜVû´!6kítA¥€öûºê‹OÛWï¢?¦ÂŧȄx™ˆZŸ¬=;«JŠ¥íŠÜl[7n!¡E’«Š‹ì½|ì½|”öÆók²qîäätéço Š¢ÁPUT¨PÙ0T”¯jìjÏDµH‹O-Z´hìØ±AAAr” ;vì¢E‹´Zmxx¸%¨â|!µ>™‰¿¥|ù_Ñ  µ›gïy¯pðñ žóâ™Ï–Šz½ÂÆÖmð¯Qc¥ókêöà#½ç¾zzåÒ¿ãTÚ9øOö å6pØ¿éÅÅWË4zµg¢Ú¸øµFÌ…DÔúôynQûÝp4¢úã2„µÙ{ûxëãê{ú.x§ÆU ¬ölçáÅ5‰¨á}d""""˜ ‰ˆÚŒÀÀ@åÙ™–îHMR—ºtérÃ3‰È²˜ ‰ˆÚ•Jàòïñ–îHMR—¸Š ‘õc.$"K²Ú).9HÔ†,‡1cÆ‚úíºô„Ÿ­ä—´<;3=áçÔo× ‚0fÌKw‡ˆn€ï‘%§¸ºÞÿ°¥û";iÚL²###7oÞ,­àm=AˆŒŒ”/‘©0‘‰‰"DQ4ˆ0ˆ¢(ý¿Q4ˆ°wvE%Ô""„Ñ÷e\ùZ÷ÃW¶;¹ö¢v÷´t÷eQž™{dŸ¦ÍFÕ«W¯-[¶\ºt)''G¾BäîîîããsçwvîÜÙÒ}!¢c.$"Ø}"gýŽKå•Cƒ_™¼p€Súj»|ß5£Ïú%[Û—Ì3mÖ¹sç3fÈZ‚ˆÚ*æB"2}ܺz:|öóùôܲ&]h‹²>s5 XÏ—ÜÜÜ|}}9mFDV޹ˆLÃ×Ã~áÃÁ_îÐýy¼±ÙN€è§8­D§¸ˆˆ¬ßG&+U^^þæ›oFDDôèÑCA="""Þ|óÍòòò÷F~mc¼jEÔØ®OÜíoo«lÌù„ùúCDDMÂùB²FñññÑÑÑ:N¾Z­V«ÕnÛ¶-66666Ö²_ocãìâïåðÙÏçS3J8ÍI¸â)È8d""j*æB²: ¢(ÂÛ 3§£ÿÍð”áÕÌL9ŠÕku:]DDD|||XX˜é«4‚q¼ž<ðz‡ÂÝÇôU²Ópr6}3Œ×`Ï\***­jà*ü§eê5ï#“u)((ˆŠŠE‘ã°~-Âï%ðôDøX¿‘ãDQŒŠŠ*(°À MãxæaùnÜö€,¡€»n{Ëw#lä¯A÷œÌ}yõÉÕÛRs *8S£8£BC'‘ù1’u‰‰‰ÑétèŒyOCd¯'˜÷4zëtº˜ ¬“"7p¢Þ† ÿoGA¨·8&¯(bÿ™¼×>?õß-2¯ÜàFA×AÈ3au""2 æB².{ö쀩“ 0׿œ ¦NºVÚ¼¤¢‘³ hÔ{& P"rÖµÒ-'‡“¯¼¾îTíEjlTŠ §çg¥óR\0Ii""2->_HÖ%==zö0kÕž=®•6/©h@?³•Ê™d¼Iç ¾ßýwí÷KTJá–¾nã‡zï?›§M+2î¯(-üý˗Ǽö¯–—&""“c.$ë’””@®g ëãéy­´yIEez¦°>R¹Ž÷ÔÅÂïvÿ}îïâû axo×ÈaÞîm¥«ÝýÍÛ…¹·¤.ɇ¹ˆšælZÑ÷þ}æRQý AìrO¨wguµ×NÕÏ}uR‚y:IDDÍÀ\HD•’^üýîô©5_d€.÷÷îâfWóÐ?¹ÐÇÝ~òhßGÌÐK""j.æB"º±ÔÌ’v§Mɯ±_nîÞqˆ.û:/T[•âÉqþ¶*¾èFDdÕ˜ I.i9e>µfÚ°¶:Þ´ìÒÓi¯ˆµõíæN÷ðÖthdSÕ3ÂýZÚ!""2 æB’‹ÚF1¨óÆ]i§u…§u…ò¦¥ÈqETU¡ ç/ av`PÞxNfš½3ÏxõUXó:â×€¦'GÀF+YH=‰ý[±+î˜Þ¢\˜SXñӞ˻Oäè 5¡¿—ã„Þ}»97©Á¿bí¹G""²Ì…$#i ­ ¤ €¼éðÙ¹×¶EÇŽcñ8ˆ…obÙ(Ì4kh†ñ®yñkàé‡9+Ð#äºC™qx{óCá•¢Ê_ö]þ=)»J_3ºùyÚß;¼ËÍÝ;šoö•ˆˆ,¹ddœB3î1ÇÜ¡  ßMˆY†GŸÀ¡ÃHLÄ-#d)T‹Üã½pñŸÃÞ ¯m€‡¦æQO?ŒÙœf Jªþ·ïòΣÙU†‡|ÜìîÞ%¤G'&B"¢ö€¹äU} ÍÈéÐÛ ÷ß‹uëñë³åBÈ<Þ_ÀØ™u„Âæ).«Ú²?cûá¬òÊš‰°³‹úžáÞC{ºšñM""²0æB’Wí)4#ÙÓáˆáX·§Ï˜¾åúÉ:Þ“{`pD û¶vN}F>ôÂO”Vèkrïh9Ì{xoW…¹î¿‘•`.lkVþt8ãóžzÚ¸¹ïƒC-©„•Æí¨¦7%c:ôÓ@nN#OŸ¹ì`3úßT-o–º˜ #^ì<¢F(tí`;n˜×­}Ý”L„DDís!YcZòêrùÜAÓ4jgúšóaÖ yã-/;GtàøÎµ¾Á×n¯wt´7Ôkd?w•’‰ˆ¨ýb.¤¶«¤:4m]kfk‡Š2”þ±«Ö+=ù@zòïÀAìUwé|{~¤Žˆˆ˜ É*ï«.˜d¢ÉBuÀ?w“­LóÆë¡AšO£ç`ôáЖOã6l»#Ä“‰ˆˆ$Ì…mÁ¬ñþ€“.YxmE“'“W·¤ú­3nÿñì_µOغ?£Î÷0$2¾w²ç/r£ó®Zý|ˆIV]–o¼Áƒ‘¦ÅžÍ¦É…™©Iwõ2ACDDÔV0’¼Ê+ [dÔyHÞuj2³ðݰ±Á]cei¿²ŽwÔdl_„/pÛƒè×ìfˆˆˆêÆ\HòúíHVÅü w"pü/Eq1f? ¹ªÔEÖñ Äȉø}#Þ™Œ™ï t<”ÿüEœ;Ší_`ÊKpvka""j§˜ IFµ'ÏäJ„.QDI ’Ï!õ" <…î3q¡™a¼ÑïÁ Çßâ“§±æuøß‡()DêIägA0åES•""¢v‡¹dT}òLÞ9ÂÍ?_ݰµEoL¸÷F¢«Ÿ,µêg†ñÚØbörÜ>;¿Æ™ý8™ˆªJØ;Á;#Ĩ‰pv7mA""jG˜ I.ÆÉ3yáÎ_ei¶éÌ4^@¯¡è5T¾æ‰ˆ¨b.$¹üv$«‹›ýSãäMHÖ£½—ˆˆÚæB’‹»}ÄàΖî…ù´·ñQÛÃõlI.7ù·4F{/µ=Ì…DDDD0‘„¹ˆˆˆˆæB²6£G€ÌL³VÍÌЯŸ>-'7»ÞÏ)ËB*g‘ñ‘5c.$ëbkk gΚµê™³¼½½ÍZÀ?ãMI2kQ©œEÆKDDÖŒ¹¬Khh(¬ßƒÁL% ¬ßp­´yIE7¯„Ao¦Š=6¯¼VšˆˆÈˆ¹¬Ëüùó5 NÆG+ в×E|´§Nk4šùóçË^®i¼É‡÷*Dù“°h@Ü«H> K—ˆˆ¬s!Ygg縸8A°ùgLŽø_åzÖ03ñ¿bêtlþY„¸¸8gg ,@hoÂ:Ì]›äzÖ0; »6aî$¬ƒÇKDDÖŒß;!«¶uëÖèèhN‡ÅKå.§ÑhbccÃÂÂä.TŸêã]9Oör/Y-æB²FáááZ­vÉ’%‰‰‰)))Z­Öä%‚‚‚†¾`ÁµZmòö›¤½—ˆˆ¬s!Y)µZ½páBK÷Â|ÚÛx‰ˆÈ ñùB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆT–î@yyù’%KSRR´Z­ÉÛ >|ø‚ ÔjµÉÛ'"¢6€¹Èòâã㣣£u:|%´Z­V«Ý¶m[llllllxx¸|µˆˆ¨•b.$²°„„„ˆˆQ=5xà9ô…»é«d§áälú:.""">>>,,Ìôeˆˆ¨5ãó…D–TPP%ŠbØ4,ßÛ%p÷Ám`ùn„Mƒ(ŠQQQ²T""¢V‹¹È’bbbt:]àD½ Aþߎ‚Qo#pt:]LLŒìõˆˆ¨Ua.$²¤={öˆœ…ÒLJDκVšˆˆÈˆ¹È’***ô3kQ©œTšˆˆÈˆ¹È’~ûí7@®g ë#•“J1À\HDDDDæB""""˜ ‰L¥üò–îQ‹0™Fe~rÎÎYû-Ý""¢fâwðˆLñûä¢3qÙ;g¨=wè3ÛÖc°U&û^÷£nÞè޷܇þ£!rÔ$"¢ö‚¹È4•½SϨ‚¤eåYûËeN‡aC¡¯Bat§±ûìþ7݆y«àè,GA""j˜ ‰LFš24”ç5F¿wm[qf>‡c»ó8^YoŽïéQ›Äÿ€™Œ4eX}OyÖþì3d}îP<¯m€½Žÿ‰ñ2Õ!"¢¶¹È”»OV¨]kì4C:ôôCDüù½Lˆˆ¨íc.$2¥ÚS†Fr§ÃAcàÜQ9Ú&"¢vAEÑÒ} «rþx’kàµÆçAðõ¥Æ^(½\çù¥E˜ • ¾8ߨv” é¶Ûu¹½±µ‰ˆ¨­ã|!‘çCû8šªMµ=èõ=q´wîî§ Ž¾Ñ`ª>Q«Æ\HÔF”€S§Füp˜ËÃa.ŠÎ~žóÇㆊ|9»FDD­s!‘¨=»úÜmÔç{N›ªÍ¿“À'ðÆg* Â[3½Œ?–gìÉÞ>©*_kªžQ+Åõ ­ˆÛ­«ÌVkUàLãö“É«[ÒÔ­3nÿñì_-iªm(:³º iY}Gå[ïúPÜtëÏ4(Ä{^ˆ}Þ·‹›´§ªH—µã!—!ïÚùŒ1yLjˆ¨µà|!‘)‰U¥EgâêÅuÄ'*'?Óv›ˆˆ¬s!‘ÉTŸ,”ï9B _\ݰQ£sWŒ‰ðéð jfkUι{æÊr¤=Uç²·OrºLí5Âý%"¢Ö¹È4Œ“…²&ÂÆ¯€Ý$¶î=ÆlÌM|¦2ï„´ÇPQóç“Î7=ëÔsfÃ×Q›Áç ‰L£øÜ×6ÎÝe}ŽPVJ/÷Ñë컎¿¶K4$-ËÛû‚¨/·\¿ˆˆÈ|˜ ‰LÃÎûÖVš¥ÚeÈ{Î7ÿ µ?J/þ’ýÛÃú’t vŒˆˆÌƒ¹È4TÎXQº5pê1ÃíÖ+l;÷TæÌJ˜X‘uÀ‚½"""3`.$¢šÔ‡»Ù êxíMCynήG‹Ïm°`¯ˆˆHnÌ…DT•“Æãö/«þD4TåzóÊÁ×+ÚQÃ\HDuTŽ®Ã—wè3»úã†%)›r~Ÿi(˶`LjˆH&Ì…D–4zôhÙif-*•ëׯ_#Î:ôžåú‘ r4îªÈ>œ•0±2÷¸\ý#"" a.$²$[[[)If-*•óönì'óì|ÆxŒY_ýó'úÒŒìÓKS’£{DDd)Ì…D– `óJôfªhÐcóÊk¥Iåè>fCõÏŸˆúò¼}/æ]Ñ\]'""™1YÒüùó5MòaĽ Ñ {9Ñ€¸W‘|fþüùMºVaëìv˪Ÿ?)>»6ç' ù&í&Ys!‘%9;;ÇÅÅ ‚°sG`×&¹ž5ÌNîM˜; ë B\\œ³³s“[ÎýžwºTPªûÊ3öd%L¬Ì×6âz±É‰ˆÈŒø}d" Ûºuktt´N§[9Oör&666,,¬Ù-ØûÝ­êàŸ›øŒñ#(úâKÙ;¦º ^lç{GŸÛè8¹Ùu©­Eþ…ÈZp¾ÈòÂÃõZí¢E‹ÆŽtã š.((hìØ±‹-Òjµááá-lÍÆ¥·GØF[÷㱪$wÏüÂ+ê½. äïmÛÂÒDD$ÎYµZ½páBK÷¢ jW·‘qGWûŠXxrUå•3.CÞlœjœ_U˜b¨(xün·ÿgï¾ãk:ÿ8€ν7{ïMDB[ì±bÖ^µ)J©=ZTQ›ªÒR”jUªFð³•ØY"Cö’y³î=¿?Ž^‘å&¹çÞ›äû~ý^¿×Éϸžæ~óœg,Ýçëë«äÒõTÑA®„¾Q!!¤’ȨÅ*ã–_1 ÙÉÜØ+IÿU˜Yìæü”'†w563*µ”„BäFq!!¤Jt>1ërP m.;S˜ž|iD^üÍ¢·å§< ­ÉLð2Uv !„ȇâBBHUiš7·èyBÃÔ]vFZ™rsfVðÙäü”w‹wOô62…*(%!„¡¸¢B+ó®‡têxŠ•f<ý>íî"V’+-È*Ì çN› uåYÔ†Bˆ²Q\HQ F¨eÒfƒQ³Å`Þ GMþߨ¼¸«Eç)7ÐÆÐZ†„¢~(.$„(’žëx³N?4dg Þ¾|ûà«¢÷è‹ÒmuŠOL!„¢rBLËÊÓ¢ç £÷ 1²…âb÷4ÔªÜBBù8Š !Š'Ô³7ï~TÛ®Ì]UÌ4Ì4”Y$B!Eq!!„Ò¼4¡ŽeÑ¥ ‹¡.CBQ7´ß !DÁ R³BŠßø—¹'ÀV'R_”žUhTÎ=„B”‰âBBˆ¢°¹q׳‚ä'Ý—çnlýgÞvä»X„BäDq!!DØÂœÔ[³óP‘huC3ZåIµù+!„ùQ\HQF¤kÖå€4?£ õi~Ê“üÔ')O¥™å?%d õŸ?Ïh©œBB)Å…„…hjYwԲ03"?åq~ê“‚”'¯Jnè¬÷"(³™„¥ßE„¢zô»˜ÂF 2t:éÖ€-ÈÊO \4s@KWÝNæZ‚\î.-A®£nèípÓsçÎÅÄÄ$''«´Ð|177·³³ëÓ§•••ªËB!e¢¸¢ Œ†¾–e»í&ðõ¯/J7ÓLäþgÇ|·é‰DZ“wÆKNNNNN~úô©O×®]yÍ+!!áܹsoÞ¼IIIá5#yP@LHõBq!!D² ² "s\ÂÂÂöîÙ-ÔÕ?ÛÔ£–¹¥ª‹Æ‹¼äÄÔÇ¡vøùùÙÛÛ;;;ó”ÑÕ«WýüüXV]‚leÄ„ª£¸¨©¼¼¼7Þ¾};<<<44Tá黸¸899µoß~ñâÅZZZ O¿¢j[}e._¾,‘²ÇÚôì¯ê²ðHËÜÒ¦gÿüô·'^¾|™§¸0,,ÌÏÏ¡ë¤9jd+- &„(Å…DùûûO™2%::š¿,BCCCCC/\¸°ÿþýû÷{yyñ—×GÕ¶ú•‘‘Àº‹º”‡WÖ]¼"NäªÌ‡Ë—/³,ë8tœúÙÊ ˆ !ŠBq!Q;—.]òööfY6Öøt<<šÁ’‡nÄD<~‚ƒ‡¢££½½½ýýý{ö,s3_^Éêké€a ÐÈævŠÏ%9/þÅÉï¡òú @‹¨A! IDATz¶”€«&We>B-ƒl¾bBˆ¢ÐþÈD½dddLš4‰eYøôÇÑCðêÅKPÀÒ^½pô|ú³,;iÒ$•|iÉêÛs¶ÝBça¼…ÌíÐy¶ÝBÏqPa} ¯Â –A6ß1!DQ(.$êÅ××7::n 1o†÷üóæÀ­att´¯¯/ïÙ•ÀÕ×¹9&­ÃÿŽŒ“ÖÁ¹9TU_B!êŒâB¢^þý÷_=e5N£G¼ÏZ¹¸L}fA TRŽ!|f½ÏšB‘¡¸¨—üü|hàªÔ\¸¾ÏZ¹¸Lš*5S.;•Ô—Bˆ:£y'D½\¹r_c Ëbiù>kåâ2åiLaY¸ìTR_Bj¡ôôô·oß*0AkkkµZmŠÔ$B!Šöõ×__½z5=Ï:3é¾S67·077ëÔ©Ó† LMM˜2!B!Š”››»lÙ²mÛ¶I¥RZzŒ–®­¢gYirrBrrRPPÐo¿ý¶sçÎñãÇ+*qB(.$„ÔL×Fôж°bY–-,êèØ÷jë5PžY‰$71^ÇF¹o÷I 2oÞ¼~øa„uš-2±í¦mà¨à XiFÒ½7Û3“N˜0A(Ž3FÁYÚŠæ¾Üy]»¦»Ö¶úV mwm·ë˜ç¿;OœýêÐ9ŸÊKM ˜G0¤’.^¼¸oß>F jÜã˜MƒO`†–mu?bï>Àܹsãã㟠©•(.$|y>÷÷YÞõœÒܾ/ÙtíõÁzº°³C×.>"¥6oåÔw¤ý?jhÁÌõ=Ðq<º)c!ðêåÚˆÜYKÏÆ_| #äE´ßo­·jëíÚsö›ýbýOwøé/‘¾X@ý ³’ïÝj¹iŸ KNª©‚‚‚ÇŒUý‘ÊÉÑÚelzüÍ{÷î)';RãQ\Hø¢­¡3ªÕØÝ×w<Š~ø(šçèЧ?Xˆ‹Ç³@„„"9s?ã%¯2(³¾=Ç‚e!)Df¢ƒpë/Üú M:cÞ^èò‘auÕåøeiA~vÔëW‡v‡Üá:uþÛÀGB~ôó&R"ÎÑ021tiôhõçÖ]zÛtï+Ò7Pu©I5 -‘D¨¡¤†¤gÒ˜a„úúúÊÉŽÔxq]hi9iø–¾øüýqÀ=,Z†‹—”B‰õ²áý1Ë"8»æáÙuøNÃò£ÊØO¯,’ ¡†Ê²/@CÓ ~çOç~óH•åøÏÝÙ£ïÌykÒÀÈ?u¾€®]†³—ïÙtoþÄ‹¦Eÿ}B’+~²fáý…S­š[oÄ$ CcMcS³íî«Ç¼“üü|–e+ýxnR¼leUR¸;{ôÏFÝž2$`Þø”‡w¸K×FôÈMŠ/zÿÓ? ˜7>ÖÿtUr$¤BÆŽË”fݺur¦Pô) –-[^»v­è áááÆ 377†††-Z´Ø»wo9 ¦¥¥}ùå—ÎÎÎ"‘H[[»AƒcÆŒÉËËžžþË/¿ b=$\V ¡PX·nÝéÓ§GGGW4zLø%uWò/oZ_G`ãfLùT1 V²ë[D«Þ8µ¯ž(<áŠéâÜmë•ï?ÿý³Q­ÆNn?U…¯•»¿\êyóVÌ[u(z¦Õw?~pø/þ†¿‚UHzzú©S§Æ§£££Âb´ÝyX6îʹ}[<÷ž(ý õqÀóÍ«ä\*R±,‚¢3ÝêÐxSeJÙ´¬3CÍJ<»iÓ¦+VïׯßË—/¹óæææò'òÏ?ÿ899I¥Ò„„„]»v 2$..NSS€T*õöönÙ²åéÓ§ŒŒîÞ½›’’RVR©©©žžž&&&7ntqqIOOðàÁ¹sç ‹î^haañÝwßU¢¾V­ZõÙgŸYYY•ZGGǬ¬¬/^lݺµeË–wïÞ­W¯žü‰S\H©Ó–v}D1ÑÒ¸I`¥ÈÌBz:¸Âw3š5­h¿o[‰òWÑ¡m}x› ïý§6œzäSÓ:uMê:˜Ö­cRÇÞÄA[¤]Åbtvé²íÊ)+=rïÐý¨€U}¾®cZ·ŠiÖfB¡ðåË—¾¾¾“'O.õk ²"ÂB~Ø"-È×00l0k±¶…•8.&dß÷¹IñŒHToä‹vK’a ]Ü ³2K½ÈJ¥ùi)E—ªÖ÷CÞžº7¸½ E‡|˜×cÄy’ž6õmõ*ô¬­­­­íûíd6lX‰899q6jÔ¨eË–FFFQQQÎÎÎ"##CCC=z¤§§ÀÝݽGòúàW¯^mbbríÚ5YØ©S§yóæ»ÍÌÌláÂ…•(*€µk׎=ºÔ_²Š´iÓføðá;v\ºtéo¿ý&âô™¨Ù›V£ú•šO71HO€Ì,… ?_±%T¬ªÖ·4Z: ‘È{¿A½ „—_^Ø{ßê3Ë?=<Îk{·a?üâ¹¾ÿÛüçã“÷"ïÆgÄKYi…Ša¡oÙȦ1wœ4ù× =ù“Eåß„Ör@RR’¯¯ï³gÏ"˾ܱÞaÐÈV›÷›6ov`;€[טz´i»ãHß_Ì[·/ëÁܤøˆ?[xv)yñÚˆ×Gõº3kdnB\£ù«PN5з­UD|öw¿‡n<òFÍFÍÖ8>í¬ŸGf|s,xËaa±ÙŠJ6;;{âĉzzz¦¦¦K—.åv&,_jj*Ã0fffÜ&&&B¡ðòåÒß?òì±cÇ–/_^´k°TEß#'&&Ž5ÊÐÐPWWwèСÉÉÉÜy†a>|8mÚ4}}} ‹'Nà¢U77·ŽSÔÕÕ]½zµŸŸ_aa¡<…çP!©®^„”…8¯#pîöü€ þø~LŒU]2åg€¾|5éŠDºÅÿógÁ&d&$d&Ü‹ ÔiÛ›8Ô1©coR§®iÝ:&uLô´Ê[£«K·çqÜqnaî÷—7ýûúÖb¯å¦º¦©þ‹ äåå|x@@€™™ÙíÛ·ÝÝÝ?šxÇŽÅbqlll:uä,Å…D-ÈÞ«î.ïfeÅ èéÁ½1ÜÃÜ ¿üŠ]{°b©B‹©0 ¨o ±a`ç,×ͺ–ò¾/Î-Ì K K -zÒLÏÜÁÄ¡ŽIÝ:¦uë˜Ö©cR×ÚÐF(rW;»tÝõáËÛá·&³Äk…œ™Y\€eÙóçÏÇÄÄŒ3棽UtvK½“ê˜Äç&Åã¿ÁšIw®ïý.71^×®”ï˜bK)¶xªÒ¿­õ­ç)) àeTæË¨`wGÃÁlêY+&:¼{­è¡–¦Ž•žiSóºŒm:Õ¶yÍ>ž6÷CÒ¸–ø<2ãydFãº=mœí*¹:c~~þ¡C‡nܸѠA+W®Ü´iS©q¡›ÛûˆþôÓOE¯®Y³¦U«V¾¾¾£FÒÑÑ™2eʺuëJ333ÈbJyܽ{÷îÝ»÷îݳ··0sæÌéÓ§çççs£½½½7nÜÈ0ŒÍŽ;˜ššrY”žÊÈÍÍ•¿<’ªºñÅòo8vÿH©ó08¼ÌÃäƒ_~Å¿)X17Ü­ÊÄOÔðð4é$×ÍY_?¼óüNtjTdjDtZtTZd\z¬œoS²“S²“‹N:ÖjØÙÕ1­[ǤNÓºö&oÒ>˜—–“¶ä¯…õ‡:¾þ;JþJ¡PXì̳gϸᆕHPÃÐH×¾nêãó6RÞ1nä¡ah¬_ÏåÍ™ß?™À²¬$'»¬Å½-ÚuÎzøÝÊëw‹tK ŒŠ, T3˜iz62½ø~’×›ÕÌÉhP{›ºVº ÉŲþ°,Ëæ½ÍIM‰:“uÆÈª½Kû­J[[Ø™i·v5 N“y™ù<2³Q]ƒž6.£££Åb±¬_ÍÝÝ=((¨Ô;¯_¿îââ`èС%»ä}|||||âãã=ºiÓ¦gÏž]¾|™a˜ýû÷O:•»'44”[`<--MþY//^¼0räH‘H 33³   99™49iÒ$®0\˜XQ©©©*ô»‚âB¯Üñ±û¿–z‰ÇAôô OC US_ %BCÝäÞ|+?£ ¹}‹¢å)ļ}•••••‘›.Oj’‚ÈÔˆÈÔˆrîaÁÚ´·2v6LCª jõ;e‰D"‘H¤R)÷ÿœ’lj$¿´‘² ¾¾¾ãÆ+ÚÉQŽ»³GËŽ[}Àmβཛ#Nü"ÒÓo8{ €FŸ¯Ú½)Öÿ´P[·Þè)–í»••”ãˆO³^‡íÚà¾pM±,X©T"ÎrKÕýÛZß~‘*•~ðGã“ðô§áéÎÆƒÚÛ8XTuªx½–_ù‰ÍLzø*`qzÂíÛsÝ:ÿ¤Ê¥ê•ÎÇÓæÞ]†2/"3_DfºÕ1ØÞƵ"ÑaÑîv,Ë–5ÃÂÂÂÚÚÀÖ­[Û´iãëë»dÉ’’·Y[[ñÅ}ûöuss‹‰‰±··=ztÿþý¹«ÜB6ܤ“¡C‡ÊYH.àÛ½{·¥¥eÑòÈùxùnݺåääT¡þKŠ ¿N=ù“Ûÿ£(~÷ÄpÞœëó•~ÙTRßûØõ9r21~5Lm*ŸŽ†PÃѬž£Ù+¤‹ßF¥EE§EE¥FF¥EE¥FƦÇH *‹Ž¥ÎUé¥FLW¦!£N¯É 23^ÿö“r^€Ê?QC£ô…~Äbñþýûûõë×­[·r†j[X—\¯Gßѹå†V_Ó±±o¾v»<)0A“eïöÛ‘/kI b#ŽëMŒJŒJ‹ŒN‹NÉN–?M)¤ì“x6¶µ€Ç…®è¡ej€-(à0h”}ßRþ‚g%’ÜÄx;InNÜ¥3ê60®œé“R©ôï¿ÿ~óæÍÈ‘#+÷ŽIÉ<¼¦ÅK?ø^lÝÿs¿]}£¢) Üyû ômë&=«ðgÙ‡´ôì­]ÆÅ¼Ü›ù·œqáäïyÛDJpÑaCƒím|,:ÔÐИ0a‚ öîÝ›‘‘±víÚÏ>ûøþ¨ëׯ?yòäâÅ‹> ,,lèС£Fòôô´¶¶ÎÈÈØºuk‡Š.ŽSÔÚµkÛ¶mÛºuë ¸»»çææÞ»wï矾}û¶±q)4h0räÈÏ?ÿ\ tìØ1''' `È!ܲ8¥277ðàƒƒCÉ}±ÃÃÈÅâgÏžmÙ²ESS³¢«áP\HxT´óŒß>3¿3ïuuѰ†E玼äU6¥Õ÷ÒÁ§†¬ê¢÷§ð;>²*…P ´3¶·3¶÷¬÷~uèì¼,nbdj䋸g¢|tmšd$]’^°ha–ô°Ìb«ÈcÍ6m ké/Ÿ>Y³À¦[¡Nñay©IóÆËÙã¥|]VãÑ£G111K—ªé«¢˜šû>”e”v?ø­ia¼¢Ò4±ëórovª"'ªq‚¢3ƒŽg6t0ÞÅαÜQž›7ož9sfóæÍ555g̘1wîÜ&nkk»lÙ²å˗Ϙ1£C‡ÖÖÖÞÞÞ~~~ß}÷]FF†©©iÿþýO*sk) ‹»wï®]»ö›o¾‰ŽŽÖÐÐpwwŸÅ…„/²Î3~#«yI¶â”SßßÔµcEOK¿¡µ[Ck7qøÓÃãäY°Ð&vŒýݘûJ(ž~=V*•䊅:º±þ~ñWÏç§¥7öhøÙ’W¿ìð`Ñ4§q3¤>xuhO^j²]ïAõFMVBÙÊDz¬@ (':tpp˜2…‡ŽbE«ÁA¡ Ã@ PØÐmC'ù¹IŠJ°†ÑѺØéY½Ÿ˜ß°aÃ’oWuuuùånë¹²”|jÙ²eË–-㎿ÿþû •ÍÂÂbûöíÛ·—26CVÈ¢¥ÕÒÒúöÛo¿ýöÛr Vôþyóæ•:«Z!S').$|9õäOG³z_÷ÿ†Çq„ꤶշ,Û®l‰y[vôÊ"3*«½cG;Æ^úrÄüˆe 2Ó#NÒµuÐ46`Þºƒm¯Y™·§ v3­þ„YÉ÷nµÜ´[%áÆ¥æëv漉x²f:ąʉ ÝÝÝÇW-^"³`_Üçååýß †®\¹FðÅ_°,X–e–Ë‚ûîàýI–eÁ¢ÄA±{м»M îwJYnÜÜ@ʾûb•¾+¤`Á"¿ÍÎ-oe`‘ißȬ[ëO27*èµ°¬¼KÕ3%ŽÞßeŠßPl<ªlä\±¶ä°UîÎÒ2*-ß’}¬œBÉG>mMaϽ[ZéjŸ­OªŽâB—võJ( …B@ JÈ~äÎDGG—º]A—.]|||JÉ®ŽXöÑ…Æ{°GÙ½3ÛŒôÛ¢¢2ÉëÛßBBcJßïD$d:¹›÷mkef àè\Z˜@¤)ï¢??-¨!‘n:]ú^‹:šÂÍ-z·²ÔÓ¦è…/ôɾÔ3sRu”ª¶Õ·¤ä¬ä?x¢!Ôháв«K÷ŽÎuŒä§¢Ì"µÝy„_(ÃJ¥W̶ï3Ķ׀ȓ‡J>ˆDïË oÞ¼Yþ›eï³dÁàÁƒ;vTöÚÚéydF©A¡¦HЩ‰Yß6Ö&ú¥Ï¯"qF8ƒÚõ‹%äMV©A¡¶¦°Gs oŠùGŸ/!DX°ë/¬å;Ôiµql×Å¥k§Núå|éi9o"ÍÛv–ädæå‰ôôHóóT]´2ëÔÒÒ?~|£FTUžÚæ¯[qÅÎhŠ]›™÷ime¤ÇKDÈy{€‘uÛU×P§ÿ-þikk {xXône©¯C‹2ЧLQ€“O<{Ö£A¯..ÝÚÕóÔÑPÔZn ¦iljáÙõÞü f-Û[¶ïölÓò¶Û›µhwÑ´&KÖ«ºt¥+M:ÕÎή* r+ø0ÿí¤bݵOÝaãäy07)þîì1Zæ–J¥’B]û~CÍÛÈ·ÇNõôôuÆ«¸lÙZ‚î½[Y–Ø^\±òsâãÃŽšõ†ðš‘Z ‰Ézõ¾³PKCУ¹…w++Š•‰>kBHUIY©ƒI³³.ʶHV¥/=Ã0æ­,vÎ}ñ7Å)u9hU‘m…gkk;uêÔR—@«(Ù >•Ðn×1¬D’òðNðî’¼<«N=«^$5ÄÝŠåŽu4…Ý›[ôn©Œ^«ÌäGáK$™u=–hêTòŸ©::}û]g!E„*DŸ8Q/ݺu»rå QdG Þ%&hÚ´éGoT8®¾É10¯RPÅ$Ç ­¯€´«ç©¨ÔH1\¡››Û„ ´´´>zådE„…ü°EZ¯a`Ø`Öb€½;{LÝ¡ãÒƒ›­,e4$#š·î?rrôéßjj\øäUzDBŽ®–°g Ë^-,øÙöúÁWÀ²’Â윷AâŒW #th2ßÚuÿB”„Þ#µÓ³gÏóçÏO™2%::ë7ñƒƒÃþýû{öTÙÀù¢õÝ]ÊŽ— ¦òúuÄ0ns–ïÝq⑞~ÃÙKʹ÷îìÑ,˲‰¾£s“Eß87,çæÚŠÿw„ðƒâB¢Ž¼¼¼BCC7nÜxûöíðððÐÐP…gáâââääÔ¾}ûÅ‹ó7ÇSNµ­¾J“Ÿž¼kc“eT]õRê<úŽÎ-7ì-ÿ6µZ¾G=988h8ˆ“”–cAn2Ãú÷ï§´IÍFq!QSZZZ«V­Ru)”§¶Õ·Šoý/òÏ_%¹bV"jk×2Ϊs¯’·IóóRŸÜ“3MV"ÉMŒ×±±ãVo¦ˆT‚½½= âssó$™B %ä˜öœe¥YY¥oßLHEQ\H©~‚vmh¾v‡AýòÓÓ ³𥘗š0o|—ã—µÌ,=ø½ê ’ZHCCÃÃÃãÎ; aÇlݦ)!ÇøÐ_´nÝZ y‘Ú€âBBHµÄJ ¹M#M#î8æü_ñWÎÐ2·løÙƒäŠ]éê‰ãbBö}Ÿ›ψDõFNI¼y ÀƒEÓœÆÍxºîK®¿°ÔÕž›,ýöÕ¡=y©Év½Õ5Y™µ&êoíÚµ^^^ožï0²òÔ3mÂk^1/v§Çß455¥åˆ¢Ð|dBHõÓpÖâÀM+5ÿÍ™“y)ïÆre„¼ˆöûÍãë­-7þ ÒÕ‹9û‡ìþR/½ØºÆÔ£MÛGÚøþbÞº}ý ³´Ü´OÇÚöÝc,ûrÇz‡A#[mÞoÚ¼mØíÜé„—š¯ÛÙtÙ†7ÿP·")®gÏžÓ¦Mc¥…Ï/Š >˜›¡øò£/€œ7‘qŽU/îþ’— 2ÞfE„y|åË-ÑÇKùeXÖjÏ g.bD"Mc3iA2jKª›­[·êêênÛ¶-êɦ¨'›´ôÀJ•8ËJóÅ Ü”gƒ;wŽ=ZQ‰Bq!!¤Zhj™µjoÖª½U—Þ–ÙyfD"mKÇOÞ-§'ÔÒ–¾‹ÛJ^âØJ­ÎˆD@k“2hkkoÙ²eÖ¬Y_ýõÕ«WÓó¬2“î+0}ss ss³N:mذÁÔÔT)Bq!!¤úIú÷ªI³Ö"]=ù©Éš&fÌZzFþùkav7E’+–f¦s÷—¼$ÔÖѯçòæÌL`YV’“-iæçÉr‘­ölÞ¦“œ«="ãìì|øðaiii LÙÚÚºö¬6E”ŒâBBHõ“xûJø‘Y©„´Ì,Í[ @×®NÃÙK‚÷lb%†¦YëÖ]{s÷—¼äøÉ„FŸ¯Ú½)Öÿ´P[·Þè)–ž]ÍZ´»¿hZ“%ëßeS‘Õž )‹¡¡!m/Dª Š !ÕOã_—zÞ¼UóVŠž‘-CXò’Ž}óµÛ‹žq_üM±§ÊYí™y&„Ô<4™B!„BHakk /9QÕ)Ž+W>>~~~Ü ÞêƒagggU„òBŒ•²,˲)+•²R–•JY‰”;c$Ôa†ÉÌ)À²}ÛuËxðæÏ#šFƦm´Ì-U]|^ä%'¦>PB·Y×®]ÝÜÜÎ;÷æÍ›””þ2’“¹¹¹]Ÿ>}¬¬¬T]BÈÇ1•[îŸTw{?•Ï;¨Â’š!øÏ›·Ö-ç±iEŸM0,øúñÑÚð»ˆë6ëÚµ«ª ¢.æÏŸÊî:CáõB ÁŽæê^ú|OÚ«¸ =Èhp_ÜÛA}º¸ø@Ýf„jâBBˆb˜5tú×ê›_ :yCÞgLAï:¬–ÐÊÊjâĉ<ŽBˆh>2QSyyykÖ¬ñöövuuexàêêêíí½fÍš¼¼¼—†5£¾"­®&õÜ:CS_Gžû ÛZK­õø+!„ ¡ñ…µ”š/ô÷÷Ÿ2eJtt´òrppØ¿¿———ò*KÍ«oFT⏻“#˹Gê ŸïS ¯!jÆ¢nè=2Q;—.]òööfY6Öøt<<šÁ’‡9ª‰‰xüEGG{{{ûûû÷ìÙSñ¹ÈAV_K [€Fž0·S|.É1xñ/N~%ÔW*‘ÆÞ ÎMÍ*çVWTЫ.…„¢V¨¿°–RÛþÂŒŒ ww÷èèhøôÇü¹`xX¾ÛáwÆÁÁ!00Pùû1ÈêÛs&†ç‘¬?-Ç¥Ã੾¬Dú÷;N§G–»¨2ƒüNÒ:ŠÍT;Ô_Hˆº¡ñ…D½øúúFGGí!æÍá=(À0˜7n £££}}U°0W_çæ˜´Ž÷ #À¤upn…×—•²¯ÎÞ;ÑwÅÿþø‘ (lnIA!!„¨!Š ‰zù÷ß`ô”Õ8Œñ>kåâ2õ™PI9 „ð™õ>k`Ùˆ‹Oú¬¾8ww±Ej„Z6­\ŠÝþ:7©°µb²&„¢P4¾¨—üü|hàªÔ\¸¾ÏZ¹¸Lš*5S.;…Ô7êêÓ{[O%F;/Ð5Ö©åg^»w?Tv^,Íÿ)ñÚ j†rB)Å…D½\¹r/MÊaiù>kåâ2åc¢I9¸ìªXߘÛ/|ÿLxôªØyPà2¨}«9 ìÍ0öûþšt;¥ ¼ù(„BTˆâBBHÅÄݹ·åÏØ€àbç¡À¹_ÛVs9¾ßÒC |6Õõẟ•SHB!•@q!!D^‰OÂ|ÿ|sóyñ Sß»U«Ï™8Û¿$x7yÈÔÕ®ýòQX7‘÷RB©,Š !—ü<òÞÖS‘Wž¿À0ŽÝ›µž?Ĭ¡C© "Í^ÛfŠ´5ù.'!„ª ¸ð%êÚ³:]š¨ºÊSSë›soë©×¢Ä"s›´ž7زi½òž0:¬câ¢ÜA”„B*ŽâB—Ô7÷m5w mÛ†ª.‹2Ô¼ú¾ ¿¿ý¯WgXiñˆÐÎÓ­õ¼ÁÖ-‹¯AS’@(¨ß¯ÛðÎEOr«BQ7¾¸íþdÿy¿1mÛ6ä=Z Å™³xú ññÈ̓ŽÌÍáX `ø'ÐPF;WN}GÚð£†ÌlP߇À£›ÂψNz°ãtÈéY‰´Ø%ë–.mæ±m'oí ìÍ»®ÿôã÷BQ´^-¥œ}ðÿxîÎÆܱœÑÃ…6W/Ê›‡D‚»ñ—Ôs„s}hh 5 ¯Â‘”gNA_ÿãétí…*ïÇUéúþöFÞ,¸¸°çX°,$…ÈLCt£ IgÌÛ =ùv¶ãÒ)Y߬ؔ»þþ㦴PRì’eS§Öó;tr—·¬„Bªê/$<âºÐÄ)bïù R|_ÚÎÝøË6ÖX±}p)6w ÒPX^£Œú¦lx̲À®yxv¾Ó°üh%÷ÓËN|ûhÏ™—ǯIò ‹]2w«ÓjÞ`ÇîÍ”±3!!„Õ¡}ðD:Zͦx={7ÈoÌF¿1cï) ƒÐ0œòƒ®.|7 ØÚ`ð@hk) #ùð^ßÒ0 ¶ÅÊãÐÑGàMÜ÷¯p ┌Ûë;Ö}qàáËÅ‚B;¯Ÿ óûʱ‡…„RãQ\Høå>¶»ŽYñW› ‹–þ9CÂÚêc·* ¿õ-›exO€›§*ðT^zöÝïNí¶èé …¹l‹gTϺ‡ïôáÿ¬uònE!!„Ô~•ìB“Q@´ôø)tìPÙÒ)¿õ-W«ÞðªÄ ƒ¥Òhö7õ8ÒåËG?üS“Wô’½y·“GœÿÆe@;F@!!„Ô"4¾|0Eùª4/>J_Q¹¢öÔŸ¨„‚¿q‡¶õàm‚\7O²êì®kŸŸ%.zR߯´Å¬ ?é$ X0B!ÕÅ…D-È¢%Wëq¼¼å怎ãI%ë[.-ŸF\º‹oÝu߯y£kaÜbf?·‘]…šô;Bj/ú Õ™–òò COWÕEQ=q6èËusˆ8>Dïªc­cjà1­oã1ÝE:´I!„Ôvµ {¯:YRǬ­…ׯáÞ˜·¢ñ¢’õ-WlØ9Ë{ÿéÔ¿o9Ðt¢E„„B8ÖRü­e]RÑÕžKªÒH»&Âÿ®*$.œùêg…,óÎc}Ëõð4é$ïýá¹I-föWx1!„T_~Šóžì?_ê%DH}½qæ,þ>ƒÞ½ÐÀµòé(¿õ-[J,.„†&ºä#yB!µÅ…„_¿þÛÿ£(…EHÜàí…óþX°ŸÏF÷®þ7‘–eŒ¿ÿÁ´)06ªjFrã·¾e¹]Ÿ#'ãWÃÔ†§L!„Ô|•ì3 ,[Œ~}qî<žâñBWöèãïÞ0‘o‚®"(£¾€K¿¾;ÐЂU]ôþ^ãaçÂGV„BjŠ _dg|¿E€fMЬ éËA9õýí ©B!Å…„?¿þÏÄÙ¶×ö™üF„j£¶Õ—BHÍCq!áKÝ®M=¦öQu)”§¶Õ—BHÍ#PuHeâb§ê"(Um«/!„š‡âBB!„P\H!„B8B!„€âB¢nºu뉉JÍ51@Ó¦M•š)€ÿꛣÔL¹ìTR_B!êŒâB¢^455 8D©¹‡°±QÁr\}ß*5S.;•Ô—Bˆ:£¸¨OOO8zR©’²”Jqôøû¬•‹ËÔo7¤%å(•Ào÷û¬ !„†eYU—÷222ÜÝÝ£££áÓóç‚aøÍeá»~g ùÍ®Y}{ŽÃäoÀðü—+ÅOËqé0TU_B!êŒâB¢v.]ºäååŲ,l¬ñéxx4ƒ¥¥â³ILÄã'8xqñ Ãøûû÷ìÙSñ¹ÈAV_K [€Fž0ça%Ää¼ø'¿Gb4T[_B!j‹âB¢Žüýý§L™­„¼öïßïå奄¼ÊRÛêK!D=Q\HÔT^^ÞÆoß¾ªðô]\\œœœÚ·o¿xñb---…§_Qµ­¾„BÔÅ…„B! ùÈ„B!„Cq!!„B(.$„B!Š !„B@q!!„BáP\H!„BŠ !„B‡âBB!„P\H!„B8B!„€âBB!„¡¸B!„B!„Å…„B! ¸B!„p(.$„B!Å…„B!„#ªô“ Ã(°¤æaYVÉ9R›$å£6IÔ µI¢n¨¿B!„Ué/äœóóSH9HMÒÇÇG…¹S›$%Q›$ê†Ú$Q7\›¤þBB!„P\H!„B8B!„€âBB!„©ê¼B!•PPPðû¼xù2.!!66VáéÛÚÚÚXY5rsûdèP …§Ojj“Bˆò=|ôhëŽIÉÉüeûàÑ£óþþóæÌiѼ9y‘€Ú$áP\H!JõèÉ“_}Ų,l¬ñéxx4ƒ¥¥â³ILÄã'8x().~ÅW_}³fMófÍŸ ©dmÒÒà‘'ÌíŸKr ^ü‹“ß#1:™Ú¤Ú¢ñ…„¢<999¾Û¶±, Ÿþ8z^½x XZ«Ž‚O–e}·mËÉÉá%#RÍÉÚdÏqØv ‡ñ0·CçaØv =ÇÚ¤Ú¢¸B”生_Rr2ÜbÞ(aG2†Á¼9pk˜”œ|Š–2&¥áÚ¤ssLZ†ÿ €`Ò:87µIõDq!!„(ÏË—/`ô”õëW Àèï³&äC\Ãð™PI9 „ð™õ>k¢V(.$„å)(,€®J͵ëû¬ ù×0œš*5S.;j“jˆâBBQž§ÏžàkLaY,-ßgMȇ¸†ÁӘ²pÙQ›TCB!„€âBB!„¡¸B!„B!„Å…„Bjµ>>>}||T] BÞQmƒTñ>x´K7Q7üµÉ–-ZˆÅb÷Ƈ l`` À” ©„ò¿xúz{Ï™5Ki…©œ’U …zºº>ýûwîØ±*Éž£%—•®ºò5£Aª2.¤]º‰ºáµM>{›/Žñòåé¿ÿþtüxŸþý%lwAªµˆHL‰‚¬Z†îÝŠ_ŒÂôY°¶ÆÞ]ÐÖª\}½½K=ïÞ¨QåT”üüü´·o­äXЇ«˲R©4;;;üõëç/^<ñBRXØ­k×Jd-PÚ’ãÕЛ,õFA>æîBûůƄbY_X8à› ¥£Šòñ¦ö4H•Å…²]ºëˆD‹ÛkkÛ‹_˜7……·ss7¾}•L»t“µI-={ûƳ -ÛhêÚ(0}©4?3é~zü͸àƒ{ü1==}üر LŸÔ@Žu1m2ví…ïv4m s³÷—òó±æHY¬^Qé €Úv 6 òõ‘«˲'O:ðóÏ'OªÜ×ð?ýU‰§j {WŒZŠC_ã§epk«÷— ò°m¤R|¾§¦…¨M R5Évéž``pÏÞ~¸¾>A!{‘h¸¾þ={û ´K7)‡¬MZÖáÑ÷‚¹ã@Å…M#«öuš-rí¸ `NüñGØ«WŠÍ‚Ô@C‡ YSdfaÓ÷`Ù÷ç÷ü€Wá˜=õUU4õÄ0Lÿ¾}DEE©º,5SŸÉhÔÙ騻àƒ&yx-¢^büWph ºÂ©Ÿj× UÓ_ÈíÒÝBKk£™™"S°ÑÌìY~þÃääS~~cFŽä?ORÍpmRß´©c‹•|oobÛÝÚuB|ÈÏûܰn¯y‘jOÀ`é"Lš†€{øûøô€[·qÊ;b@?^3øèÑòÕ« ÷íÚeddÄz´}×®bPƒ”©hƒTM!·Uv3MMefÊeWé]º÷ýô7{ßO?5iÜXvž¿‰Bå|q?r¤ºOÝR+\ÃÐ7uWNv"Mc-=»z´gûvkkkÍ›5;r쀱ÿ}Ë)??ÿÆÍ›»÷íЫ{wî¤üe(Õ•k׮ݸakc³éÛoÍLM‹^jááa``ðèñ㌌ CCCîä…K—ô¬Ñq!€.Ãqï<\Äîy“‰/Bψ—¼Î]¸°gÇK ‹Ð°°¹_|ñ¿«WmllöìØaei;eƌdz,[´MRƒ¬tƒTM\Èm•ÍӘ²pÙUz—îGwéØÀ£'O*7t”³võêõ7øzÕªo7múèý¥Îäz›?:GIþùS„k SX‘–i^vLBbâGã²Ú˲¿=zìÄ –eë×ïÒ¥ €ˆˆˆs.œ÷÷=r䘑#+4å¹Xƒ¡¶ªF_~‰Sø&O„{ñ¿*çMLLÉ“©©©²c}}ý93g®Y¿~מ= píÆ!ƒÕ­S§Ø#³g̰±¶Ð×ÛÛÿÒ¥'ÿý¦åº.ùøpM‘a˜AܼuëêõëžçΚÅ}W”,´-((HIIá:]<Ûµë߯_EËP*ÿ‹L?¾Øw0‘HÔ±}ûs.ܸu‹K*77÷ÚõëîÛÙÚV¢.ÕÃ`Ú&,ìà{0üK4hÍW^ çÏ·´°PßÉ €T*]8o÷ëÂÎÖVGGG,hél¢Yé©âõ «‘ÌÌÌ_kïé™™™yøÈ‘vE+THBbbýúõ$%%9ׯÿÑûË™-øÑ9JòÏŸ"Ê'Ê;‡´¬¶wü÷ß?ncm½tÑ"ggÙýÁ!!¾ûîȱcšÇ “¿HÅ µUõbb‚‘Ÿà‡ýк•¢R•ç3÷l×®s§N×oÜX·aƒ‰‰I©C´eã·ìíp½×^GDp¬[Wv'wüúõëb)´lÑ¢åG‘Жac##ggçžÝºuêØQöG‘üe(7?¬Y“&¥^íÚ¹ó¹ dßè·nß‹Å5û%²Œ‘ÌÀÑõЬ+5puåda6lð~n‹ ´¿~©AVºAR\XÜ¿%€pùþñJuæìYîëóÌÙ³ŸÍ˜¡‚‘¯dÛ‹‹ÿõØ1o×­+ÖÍÖÀÕõÛuëfÍ™søÈ‘Î:Y[Y¡R¨­ª—·é8ùç»ão7aßnhU~yšŠroÔèú,ËèÛ·üÁUZZZ ÿ±#‹èè¼_¶„ëB΋U¶†¶U,CvN==½R¯º7nlfjúüÅ‹äädssó —.ikkwªì ÆÕKF Îîw¼{¾=ÍÒ'N¨5ÈŠ6HZ½S^¿ùfã7ß=(‹lLý•kצ̘ÑoРy ÆÅÇsW7¬[×ÈÍ À·ëÖ¹—+V!å Þ –]ânKNN ÎÍ=täÈäéÓû 4dĈ_}\2M±Xüõºuý ªJñˆ¢”ÚöΞ?/‘H|úõ+õÝ«µ•Uÿ¾} %’s.pgJm-²“¥6j«j„e±aRRñÕJXZ 2 ?PZæ‡533ðϹsÙÙÙåÜÌ}çÉvôá¾ürsse7p‹…éê(o»*–ûÎÈÈ(õª@ èÜ©˲×nÞŒ‹{عcG2&–Ö$,‹=óñ6óöÂÌ1¡ømƒªËTjmÊ«i“&M›4)zP¾ó.|·e‹±±±©©ipHÈÞ}û¸ó²µŒø  073+9J,/\²äØñãNõêMž8±Ÿ>AAA_.]ú2(¨Øã²yXü•ȯԶ÷ðñcžíÚ•õwéÑãÇòdQjƒ¡¶ªFþ8…;5];cé"0 Nþ‰‡rýãVÝÁC‡²²²Ö¬\ÙÁÓ3%5õÇå…¤‘‘êý÷ŽŒ›ÿYdå¶ðˆõêÕ“'k¶èúx•UÅ24pqpïÁƒ²nà&^»~ýâ¥K¼zö¬Ji«‹s?áÑÿà3 íúcÖV0 ÎîÇó[ª.V Ô +Ú é=2_>¼iýz÷Æ#£¢fÌžý,0°r锜-¨§§·uóæòŸ277;jT±ùS~þ9<<|Ø!“'NäδhÞ|éʕڴ~}ÑÇ‹ÎÃ"ê‰Û»™:Sª:uꈑo‹çRLEQ[åKH(öþˆ† 0i"4÷Àð¡8~6áà(ãu’¢Ÿ÷÷ï×§““Óg3f< ¼pñbçNZxx”¼™eÙ³.èØ¡w¦[—./^¾ô;s¦«+7õò¯Ó§pk–ƒ›L••UõÍÄ+]ŽwïÞ?þùða· dKäääîõŸ‹³³µuhXXl\œ­-×Ë^³½~†#ëP¿† Û£ß4œù»çã»ËÐU›íß©AV¢Aª{\\PÐ=66Ÿe÷YX .ñë/¤  gll‘袭­Žšm5;mòdîÕ›q‘ã )9[аR’eÙ‹—/à^ç4kÚTWW7ðùóÜÜÜ¢+jVzQš¼¼<|8B¥îÅXqƒf>ŠÚ*/Äb¬ùXµ ÿýÆžü)îãu¶íIJÅUI~ÇîÝe]š9}º€avîÙc``ÀíÙhbb2sêÔM[¶lÛ¹sïŽE›ßÆÍ›­­¬Â_¿¸¿¾“Sï^½¸óÞ^^ÿ»zõʵkééé.ÎÎÏ_¾ |þÜ­aCo/¯ò Ö´I“»›}}[4o>pÀ€ªÔ±Òeàtlß¾{×®ÿ»zuæÜ¹MÜÝMLL’““ƒ‚ƒ·oÙÂM`¦k—.ÇŽÏÎÎþdèпïyn6¶Í‚†æî†HãÝÉ‹ðä*¢ƒqp>Û¦Òò Y…©îqa •&&+SS¥¤xjk[ ߯9œÇ²S“’¤Àêèþßz""a•ÖIVÔ Í·oß¾MOpà矋.<*‘HX–MIIáâWN¥çaÕxâŒWþC¤Ò|çvß›Õé[ÊՋôôìÜ{ù`¤­¥%ÎÍ‹ÅeM(9´™oÔVy±uÞÄ`ù]fBS+–búgð¿„ŽíÑY®n†R=¾¬KÓ§L9wñâ«ððÙ3gÊBü®]º\»yón@ÀÁC‡fMŸ.»™[zÃÈȨ¯·÷Äqã44ÞÅ "‘蛯¿>ò‹µ:çIDATtäÈõ7=ybff6tðà1£F‰>¶NÙÌiÓ233ï?|˜›—WůáJ—Ã0ÌÂùó6hpöüùg ÃXYZvéÔÉÔÄDvO×Î?Î0LÏ"ûLÔT–#þ5>Û«÷j¡¡…Ù;°¬/nüV½Ñ¶øoGe£Yé©îq!€i††çrrnçæ~žœü›••ì[bujê‹üüïÌÌÜ”»>¶œÔíOF®{I ¤½}[ô¼«‹ ÑÿÍòéÖwhúEäã ¿6°h¥©ó~·T’vgÀºxúò°³³ {õ*úÍÙ ÅDFG¨Ž‹¨Q[}ïâe\¸ˆÞ½Ð«Ä2õ0y"~ØÍ[áÞ%V2û(yâøýú è÷ÁV{ Ã|µbE…RÓÑÑ™>eÊô)S*T+KËï7n,¿xòÿ)R~Š¥S2Y†aJ~Eq¶UË–Üìœìæ)\?‰ÎÃÐiHñKuaÄ"]ý‹Ñ 5Œ?²0k)J~òòœ9ùÛoò$%C ²|Õ .;ÍÍ;ÇÆþO,>”™9ÁÀÀ¹œœŸ23ûëêN¨ò›þZ‚[úœeÙ5«V•µ #‘‡µË¸´˜ËI÷^ß[Ñ óÀ»?¢žlÊy\¯åj#%£¹‡GØ«W·ïÜ)+.ü÷Îî¶²RPÈj>P[}¯WR"B™Q#0j„KCÊäwæ ¯Z°laÇÁè8¸Ì«>³àSæ2¦DyªÒ «Ç|d‘h½©)€U©©……±……Ÿ''Û‹D¾ææêÕ)§–¸¯]]ÝzŽŽ,ËÞøPÕ%ªæS›o…"½·ñ7_àÎ¥Å\N;jjß˲¾’¾§ûöî- ÿþ矄ÿÖk-*>!៳g…BaŸÞ½‹ž/ºÿæ©Ó§KMY…ñ"µUR¥§§_»qÃÐÀ me÷; DªØ «G\`¤¾~o]Ý–ý,)iFrr†Túƒ……ñÇ6ת帱eYYY܃ðÃþýÅæ¨J$ù¶ë&-=»ºÍ—ˆ|²17+*_~o¹¦®M½Vëd݇|³¶¶;fŒX,^¶r%·ü½LpHÈÒ•+ʹãÇŒ‘-jÍ CäÖÓ—H$ÇOžüå×_‹¥Y¬Á(µÕ꫉»{w%m,®žÎùûtëÚU£V rPWÔ «Ø «Á{døš™uÌË È˰Ôظ×ú¯¦ŠÍŸêÙ½û‹  ó.Ìœ3§M«V¶¶¶R‰äMllàóç{wì077Wuy«‹zƒÓb.¥Å^ X F )Èrí¸[¤i¨Ì2 :477÷øï¿Ï™?¿«k)ËFFF†½zÅ0̘Q£>:Tvs«-®ß¼¹|õj§zõ¢¢£322–,\øÍ‡Ãe8ᮢ¨­V_ÅVª…F~òÉÈO>Qu)È;Ô «Ø «M\ÀB(œmh¸&- @7%β¬¾ŠÍŸbfî¬Y-=<Μ;÷èÉ“[ÿþ«££cgkÛ£[7=}}U¶ÚaêµZ›ya@fòCöîs Ì•=1–a˜ cǶo×ÎïÌ™§¡aaÀÊÒ²¯·÷€~ýŠn¾ `æôéùùù?~ÔÈÍmÂØ±E7}wâ&ÜUµUBQL¥Çqóm+·2·íU’£c…žJ‘HºÄÆ&H$\54.ÛÚjWpίED·š) ÷ï«üajUo“m‡¿¬ÐSqA?E=Ý À½ç =Óï‚SÔ‹+ã2“î÷í·UÜbŽÈC}Úä»Mÿ®^TrIеè·Ÿ:Q·6ùÛ%#íj“ê„k Õf| ÌNNNH~²°°‰B Ö¥¥©ºP¤V+ÈK ù…;~°T*©äÒå¤Vy·“ai³…x”˜ø>kB>Ä5ŒäâËÒó‹ËŽÚ¤ª6qᾌŒKbñ##=½ææ ðCFÆÊn"BH•±áK r“\<}5u­Å¯¢ŸùªºH¤Ðà–® Qj®Á!ï³&äC\êÔL¹ì¨Mª¡ê>ÍÏÿ:-­¹–Öccµµg˜“œœ!•ªºt¤6Š9ü6îºMÃÿ·wçaM]ÛÀ×a$¨L‘Q¦Ëà8`«"(ÔJeÄ÷D,ÚZÛ: HEKoµµ_õÖE¸Š("µŸ×k¯Šµ µÎEyL"ʨ¢‚€ pÞç6 C’È„¬ßÇxr†¸ôìì³×^+ ,æÙNù€¨-=öæå-e· ©º±T­Ò…ýßÕÕÿ:ù×¥êŽ Œ´Ð¥¨\ÿ.>¤øëÒH¥ ‚~akW×ÊW¯qhäHÆŸ ¿Ò×Ë`<åñ¢_¿VnóÐÔÚPTu—޳…S8Œ0šj:z9<Ήæw6+¹qHµøùd³¡¸bãAsËHb㡸d$›@MmD¨;*&Ëò!ùk åÿm…ì‚䯡,0&UÓ ènzýúIgç.k¡g-‚H`³5 âç––smmJljø¼¶²ìH55†Ý´Ý„ÚW‡åÎÔµç¶ÕVä}¯Üæ!Çb±Ö‡‡iç`I(\Ì’×\×/áb, …´sA¬UJ[ #33bưõë¯Ý¸!—&!•$ˆÉß~‚p7¸vJ^s ëžÂµSî¿ý“*KÕíŸjm=ÙÒò¿Ã†-êµ8…#ƒ­§÷]CÃuuSÌÍÔÕ•ÒB4ÔTä}×ÞRi;u‡ö0KÁF5u-»©; ~[TW™¦oîe0j®[ˆTܤ ¾ÿöÛØøøWÏkaûNy_n$›6iÂñ»]½~}ßþýÔ便¥3ÝÝåÝ0Y¡’(1­u 1ù²ºî@„Ü/‡1©ÊT½_¤£¤£#êÕ0]Ý0]]E¶ qu•éu¿°­ýÙV=°ôÆX8ETÝß]žûÍp¶‹¦6®½ŒDr™4éHbâNŸ.*.~þâųîe]dÂÌÌÌÔØxÜØ±‹.¤SöàÜ… ¾fÍ{õ"æçx÷zê§¥¥emeåïë;ËãÇKÏž??›–vïþý/_vtt0 }=½Q£F9ØÛH(¢<*+˸x± °: S[ÛÐÐÐÒÒÒÁÞ~á‚}e-(þ–\U]½6"¢³³ó˨(3z¼Z]]ild·g– —cÀ˜Ä˜¤¨z¿!•¶òe[‰\ðÙtÌ Ó1+Ù4xijj.Y¼XÙ­øË“òrð˜9S[[ÛÜÌL̛̞$Ir¹ÜòÊʇ¥¥;cb:;;çΞ-ا¨¤ä«Í›;::,,,¦»ºj1-­­Ïž?Ï¿{÷N^ÞlOO‰÷`>Ÿððaªg`me5ÝÕUSC£±±ñIEÅÙÙdgûx{÷yV“C}T.—ÛÐØhldÔç«–…†:räŸ NŽŽ†Âþc×.’$£7nTåN!cR|{†HLb¿!„´µµ€¶¶¶Ä=ÃV¯þãÙ´´Ä¤¤S©©Â÷à¤ääŽŽŽ—/  „ pÚÛóòó‡Ñ(Z“˜”tîÂcã_|1vÌá—jkksîÜéó çÏž•xriùØñž~~Ù·o?((ˆ‹ûî›oo9éèÑòŠŠµ«Võ¨?„èÀ˜C~19òNB)!e)˜7w.<}Ú-UáQYøûøô8!S[ÛÍÕuÄðáâÏùøÉ“ôóç™LæÛ¶õ¸€‰‰‰ßüù*5üFÄL&37/ï×ÌLjcöíÛéçÏ»¹ºR£Y¨0&û§ß1‰ã…ddffdeñùüE ¢I¯è-†1‰úÓÞ~üĉ«×¯××׳ =fÎ Y¼˜‰I;>!1‘ÚÍÛÏO‡Å:õïÓ?3UÉM‹ÁÞÈb±Þ¼ySQYé`oßÖf\¼þ>>¢“‰Ñ{.§½ý?§O_½v­öÅ --­qcÇ. ®.8äòÕ«ÇOœx^[kog·iÃS“’‡×GE ïöSr2›ÝÇìac#£ÏW®Üw89yÒĉš{ãâŒFŽŒ ëGÏf(À˜T͘ÄñBq¨d¨‡¥¥e—–*¶>R¬îîŒ> z;’騾¾žÇ}ÓÚP¨k<]—ëâ·sš©«Q__òÄÀ˜„!“2ôkffqIÉ 7·è ‚ IrûÎ7nÞ̼xq¾·÷h‡ÑÇOœ€¥Þo$êêêªý:ûÖ­”cÇ444>\²DøÕeK—¾zõêúÍ›ñ$&%¹Lœè:mšëÔ©Ã%=­£Ô¾x£ÌÍ¥|£}8qòä“'O‚W,_Nmq™4)zóæ£ÇŽíܾ]xÏ£?ý´sûv'GÇʪªÏ×®¥úl6{ip0͇ ˆðµk?_»¶¨¸BCBÆa=0&U6&•Ó/ïì|ÿÁƒo”k#Öðx`cmMÿúÉPý#H¡êêêjmm}R^^XTTXTÄçñf½÷žÌ/'Ê[“L7ö¶¶EÅÅugÓ/¬«L'I¾¥¥ £û“‰0&‡NLÊЕk×`Ÿõðˆ ˆ¾¾7nÞ¼ríÚ|ooiÏÖã+„‰±ñ£„72ŒèßÏÏO¿páN^Þ­œœ[99ñ³<]±ÂÉÑÌÍÍ CJ ¯§˜œ’“]\Öü·Æ¤ÊƤrú…T©ì{\®"û…÷¸\0æ±ýd¨þé‘BE’ä©ÔÔä””S©©Š¼&ÓøùøddeÕU¦Zúê™ö ’­ŽÖšª»ÿiŽÆäPŠI*¯¨áOŒú½¼¼¼g ™4·´455Ípw§n]=1ÙÅe²‹K[[[n^ÞÍ?þȾ};ëÒ¥[99;¶m£¾¢¿xùrù'Ÿ1|øÉãÇ€Á`p¹\‡CsI9Q›š 9%„&Tñù|’$ëëëÍ…†<ÿŒpTIhjj:ûË/Ôï»ccÿ¹w¯´ßý†ŒI•IåÌ/¤JeÇ55)ªH7ðâšš _Uº6e˜ ê DUU•b®(|é!žLgfföQh(<¼ñyåÝ¼Ž¹\†ìª«LéÏçqÜ\]{?!¥ cr(Ĥ q8è>ÔA}µhãpúq¶Ã ÔO\LŒ¶¶ö©3gJ>³?‹Åšéî½qãIIï¾óNssóÁÇ©—4ÔÕG™› ~LMM©íÆÆÆPQYÙæ £ÆxÔÔÔ„8ØÛ;;9it_Zyàÿ¬H’ŒÙ·ïuCÃW›6d³«««;6Às¾­0&U6&•3^àç—yñb^]ݦúú††òîœvlª¯ÏëèªJ·`\Z8JLþ”ðQgNžÜ““›»ß>éF5H¡50%f-ÑLk’Ø$L¦ó÷õåóùGRRjKSjKS´tÌ5µÙ‚ ȧ¦Æhz‘ @Àxg爰0iÏ€19ÔbRV˜L&‡Ãioo܆©gÖÀŠ…†„:rdwlìþØX‰õõõõׯ[·$4”šê†††‡zïé8n\uuõÕë×8?oĈ@’äw[¶Èo”]à—ôôÿËÍ]8ÃÍmĈÑ_}6-mÚ”)Æ—÷¥ŒI•IåŒ ªtÿØÜünMÍÏ--Ôä?™«áñ~niy·¦æÇæfšUºz'C‰ÏŸv(9ùîýûv¶¶êRŽýÞÊÉ ê³–è§5Ñi&Ó.XpøÀÉ..jjjêdcKý½æW¹²úáóÚÆ;;µcÛ¶~|°“C0&e‚z@V)4èû¤¢lllxf?{;»§OŸ¦Ð£n„š’f½?{6\ÈÈ Öœë7‹ecmM’dn^Þ@ÎC¡V?¥ìñã#G:ØÛ‡.] œýý &6¶µ­màWË`LªlL*-YP¥»ª®nM]¼/G³J·°Þù>âó§„ÍËÏOˆ‹311¡9.—{ýƇÀOOj£Ä¬%úiMtš„Ét`fföý·ß’$YU]ÝÜÜ,Ã36ÌÊÒr ]“C3&n–‡GQqqÚ¹s£¨8¡æõ{&ƒ€ººúº5kÖEFžMOŸîêêìäDmß¼uëûsæ¼ãâ"<"B’ä™ÔT 1ù}ÌèÑs¼¼².]ŠÞ¼yÍgŸÍœ1Cðå$ÉÒG.dd|¼l™®®®ÄøûïÙ·/1)ÉÆÚZ8U‹Çç4¿&Qƒ[---¢rW9íí?ìÚ¥©©ùeT” èEèÒ¥wòó+*+7¬_OçBCÆ¤ÊÆ¤2שQÁ*ÝâÑÏŸZ·z5ðÊU«¨_:;;ëëë©1×iÓ|æÏYKZZZôÓšh6 “é(AXYZ*»’aL":æÍûû•+—¯^mjj²·³+,..(,;f Ub€ìlm,8š›O=̽s'÷Î uuS–ŽN'—[ZVV]]=’Í^ùñÇO¶zuWWץ˗wîÙs0)ÉÎÖV‡Åjmk+//ohl$â£eËè4o¶§gQIIFf檰°)ï¼cffÖÅç×<{VPXx0>^b*e¼³ó휜Ý{÷ºLšäïÛG…ôý>}ö,*2ÒT(¤ FTddxdä¥Ë—§Mê>]k “*“J^¿PÕªt‹G?ŠæÝ«æÏ*=AèéêÚÙÙÍž5k†»;u—˜µÄb±è§5Ñl&Ó .“ˆ m[·;~üÚõëù÷î.  UÎUZKƒƒoܼùâåËÃÉÉëÖ¬€Û¶Ý/((}ô¨¦¦æVN—Ëe0£ÌÍ—,^¼ÀחΊqšššÖ¯Ÿ7wnfVVQqñýx<“Éen>ÛËkŽ—— bÝêÕ“'N<÷ë¯ù÷îÝÌÎf2™æff^³féО°êÓO›››sóòÚ;:z߃/_¹ré÷ß½<=={åìÿÍÆ&ôÓSRâ÷ïw;V_Êuìßb“*“¸®µd›?b+^C÷¬%áíT  MM‰;HÛáÄ¥ÃGŽP‰KŸ eì#Uƒ1‰hb2™Ÿ}ò‰˜Nü_½ø}´µµS’’„·Œwvïì,m#{srtìsÁ1­êÝH‚ ÜÝÜÜÝÜhž¡÷c#£˜;D>ë½÷Ĭâ´(0pQ` ¨W‡2ŒIÕŒIìJANùS¢HÌZ¢®.ô&L¦t0&BÉÖG–‚üò§ú$1kI¶iM˜L7aL"„’!ìJa–‡¤;Ge†Ë0J”HLJzÚ=)‡Ççóù|:;Ð$*qÉÚÊêU]]Bbâß’ŒI„B2„Ï‘¥ ×ü©>IÌZ’IZ`2Ý …1)Ÿw‰BCö ¥ ïü©Þ$f-É$­ “é/ŒIŒI„’!BübÙâŽ$ —.„†ªÊY¿C«ß0&‘(“HÕ`L"UCÅ$Î/D!„BØ/D!„Bì"„B!Ì;A!y»“£ì& Ô Æ$û…!$_ß~ÿ½²›€P7“Hì"„¼øöªgraL"ñ°_ˆBò’†« ƒ1‰Äü„B!€ýB„B!DÁ~!B!„x<„DQV}'„DQ|L"„ÐàòÿUÍ—±º,ãIEND®B`‚quagga-0.99.22.4/doc/fig-rs-processing.txt0000644000175000017500000000430012000052240015052 00000000000000From 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-0.99.22.4/doc/fig_topologies_full.dia0000644000175000017500000004363012000052240015473 00000000000000 #A4# #RF2# #RF4# #RF3# #RF1# quagga-0.99.22.4/doc/fig_topologies_full.png0000644000175000017500000002045112000052240015516 00000000000000‰PNG  IHDRÞÞÝ)àsBITÛáOà pHYsÐй‹çŸ IDATxœíPgþÇ?›AÐ 2,§ 7sP¦¨œµéÔ™ÖÚN¤ˆmVë9zŽõ¬Ž uŽŽ:w8Úûë0SF«-\ýŠ”V-ïz¤*Ò±TÐk¥"Ü8õ=F"‰ !ÙçûǃKØìn6ÉþLö5ù6Ïóìgó~?ϳûì³Ï!›‘‘«ÕÚÑÑÑÛÛÛßßß××çt:Ýn·ËåJHHHNNNKKKMMÍËËËÍÍ-((HJJ §’!‹¾D8Ö¼uëÖáÇ[ZZÚÛÛù—£Óéžxâ‰%K–”””ää䄼w ±‘WßP¬I’dSSÓÁƒ[[[ñ½^_PP°hÑ¢ÌÌÌÌÌÌììl“Éd4M&“Íf¼}ûöÕ«W»»»;;;ÛÛÛI’‚ Ìfóºu늋‹cbbB> aQо(H’¬««›1cÎWVVÖÚÚJ’$ÿB\.Wssóš5k¨p³²²¼^oPÁhŽ¢ô š?þ8ÞYzzzmm­Ãájg4GMMÍܹsq™yyy}}}á¨JÓ——5Ýn÷Úµk ‚€iÓ¦ÕÕÕU¸ñx<‡JOOÇGEE…Óéªp >(SßÀÖ¼víÚc=±±±Û·o³&±át:·oß®×ë`Þ¼y?ÿü³{ÑðG±ú°æ… ¦L™‚O.\¸ Pœ¬\¾|yΜ9œœüÕW_‰½; %ëËeÍ'NLš4 ž{î9»Ý.h¬Øl¶%K–€N§ûä“O¤Ùit¢p}Y­ÙÜܬÓé`ýúõ_;{½ÞU«Vá.æÄ‰Rî:zP¾¾ÌÖ|²³³e?yW#jÔw̚ǀ9sæ(vfÚèè(>_nhh;õ¡F}Ǭùä“OÀ{ï½'_lyÿý÷à©§ž’;õ¡F}!ÔÓÓ‰‰‰ ;¼wï^||Ä"¾øBЈ¤%ÔàUªï¸5‹‹‹©DsçÎ%X0™LË–-kjj€0–ÆÔ©Sýóz<žÎÎοÿýﯼò >y§X¾|9œ>}:èã¶Záé§áòå 3*‡Ë—áé§Áj 6M_YÄ>räÈòåËõ«_FƒÁ‘‘ñÆo\¼xÑ·ä ú 1iÒ¤‘‘ªiåù ÜâÅ‹].cãÌóW›2eŠo®;w>óÌ3ñññ¾i| ÇÄÄ ›ÍÆ·ŸhkCf3@))Hª©_¢`·£”€ÌfÔÖÆ3“¿¾Ò‹{çÎÉ“'3¦Ñét JöÕ×€‡àóóócccýs^ºt‰ú›$I»ÝÞßßæÌüÒ_|±gÏž;v°—‘‘qòäIŽèñ¼,Š?ÿùÏ^¯×`0þðÃÃÃôô“'O.,,<þüÙ³gñíW.¬Vصk¼™)/‡‰¦WññP^[·‚Õ V+˜Í°c˜ÍÜ™8ô•L\·Ûm·Ûó›ß¼ñÆø±L‡Ãñù矗—— mذáÑG-**‚‰úBUU¼õÖ[¾Õ‚ªXlu±±±'˜={6GÅÊÉÉáY¹1»wïnkkÃcÂl1lÙ²ªªª¸ ¢ZJê£ö&C5œÔ'P ꯯ôâÞ½{÷ôéÓþwò>ýôS\ÔÒ¥K©”¾ðòË/ƒßHlÀèI’œ>}:èõzA¢÷‡-†ºº:X±bs6SâOuuÈ‘(‹êj†£c7¨¿¾Jãõzñô¼äädj#¥¯îÆ€oñ‡ |Fˆg¤J ~xôÊ•+ô/ð…ã…BJ ¬_/Ep°~=¤¤Ð7²{úJ&®N§KII€ÁÁAj#¥¯îæÍ›ššT¡ׯ_ü0ž”¤¥¥À/¿ü2¾‰Ã”µŸeú‚Ï8aúBÐW2q=Ï­[· ŧ²ë‹/h¼Ümþèè諯¾Š?~\¤6Ÿ-lʤ¤$„Ø»oíó ‹÷×W âb¨AÀ²²2} xøÊ`0p!tÿþýëׯ···8pGmÞ¼ù¥—^âÈåõz‡††Ø¾5! '$$@¡ÓÚ _´ðà*þ·Ok }e×ëõâËÿ˜˜˜·ß~›ÚŽõu»Ý´‰R‡¾RSS?úè#ŽÙ“ÜÙ1Û¶mã¨Rl•ÛårÀóqqZ{ɧí|Öd¢é«qBúÓŸpÊšš}tèlœ={–{ÇáG¯uèaš2`‡.£¸ï¾û.Nö—¿ü…M_ÈÊÊ€Ÿ~ú‰Ñw'‚§£@NN÷ŒT*÷ArÀf;¾>ÈÌÌßР3r„a?ò3%Æ__yÅ%IrçΠÓéhí%†Ò,XV«Õ÷k6[$I݃ٸq£HÑsÇpîÜ9((( gà0hdŒ·cüGÝYL‰ñ×WFqI’Ä#êñññŸþ9cJ_¾Vǃ!¢¶¶Ÿ¨îß¿ÿË/¿ä“KXðˆ&µ4Þ8f3´µA[ý»¨©‘"8 ¨©úFöc篯Øâ"„Þ|óÍwß}wòäÉÿüç?ŸþyÆd”¾ºÜÜ\øî»ïxî`æÌ™{÷îůZµÊf³ vàÐYO˜ØDÚ·у‡öí›°…£B@PúŠ*neeemm-=ztþüùlÉÆõ=sæ ù6ªÜC_^¯wáÂ…8ÁÊ•+…móÆ€{¨“'O.‚ÖÅGÀ§ïY&¿ùGþúÊ".u_þøwJJß“âØò÷ôôPw±×ûÉšÚ¤8þ¦ÄpLŠcË"¸¸wîÜy衇@¯×߸qƒ#¥¯¾€*,,€ææf*EÀèB{öìÁi¦OŸ~çÎ0£Ç8}À1€ïF< kþüùA‹Ðƒªºá¬®Ê”4}¥wÛ¶m8KFFÆ,à”§N¢ô*ß¹<|¢Å«ç€Åb¡Ð†fM¼j-Ë–-€]»vUì8--!fT—/‡–¦¯ôâ®\¹’[V*˜+VPú2?¶Æ'z„Ð÷ßO™‰2~hÑcZ3..N{l-XhúJ/.OkÒ[Óö Ô¨¯¶DBT F}µ…e¢5ê«-Ç-¨N_mÃhAuújK¿FêÒW[0;ºP‘¾Úk¢ 髽œ%êP‹¾Ú+­¢Uè«ì '¶lQ÷t!eb·7oÞ¬#™õ áE€ù_¯¹i@&²XP}=â?Nƒ› Õ×#‹™LàÄ–-ª|}*Fæ—ÛløGûh ‰Žÿ1m6µ¾t#ó«Ü-†ç³4òÑ‘ÔÇbÁ©dÖ—ÀÖD¹Ýîµk×Ó¦M«««ð®ŒÇã9tè¾O¥×ë+**œNçø×õõ\¶jõ‡Û‘Ô§¾žÊ!§¾ìð²&¦££ßé€ôôôÚÚÚ0k˜Ãᨩ©¡žÌËËëëë£'¢õéšGÙàéHŸÞœV€<ú²„5B$IÖÕÕ͘1ƒšØ[VVÖÚÚT%s¹\ÍÍÍkÖ¬‰‰‰Áådeeá•p™30öél£qÌ£üª¦êq:Çi4ñ+=èÍiÈ£/ â½47I’MMMlmmÅ[ôz}AA^ 9333;;Ûd2F“Éd³Ùoß¾}õêÕîîîÎÎÎööv¼Af³yݺuÅÅÅÔa0ÐЯ½Æ7¸œ(-…ÒRÈÍ ö¸ÔJw746Bc#ôôðÍR_eel_J­/A™ÆÍ›7wïÞ½`Á|šÂNWTTTUUuåÊ^»áÓ§çä ÊJÔÕÎ᨞®.TY‰rrBèÍ‘H_Bi5ý±Z­½½½ýýý}}}N§ÓítºÜî„ÄÄäää´´´ÔÔÔ¼¼¼ÜÜÜ‚‚‚¤¤¤àv°t)|öÃv‚€¥KaçÎ(j#ùÐÝ ;w§Ÿ£¸ ½« =ª¹sþ¾öÕë¯mƒêëÇk‰0/f*Øç Ú"íBvþïÿÆÝ z=€×;öodûR|}µV3 hm'eJˆt_J‚fÍðÀæ++›àK½^óeøèä@ý0vg‘z#!š5ÃãèQxýõ M&x½ðúëpô¨L1Eš5ÃûÒ÷2_ ÁƒkvÍa Y3Th¾4 ¡Àðàô]sgxh—A!áïKßëÿñÎW^‘#J•#ÒP~$ß x¿Gö•j$@»Q©8xÞ‡ŒxwjÖTAÝlwjÖT!ÌÛˆ`wjÖT !Ï'ŠTwjÖTaÎs‹HwjÖ”Aæ_Fž;5kÊŒ€ó‚#Ìš5åDðùê‘äNÍš²!ÒsãNÍšò êó=‘áNÍš2 ÁsgàNÍšR#Ùójw§fMI‘ø9]U»S³¦tÈòü¸zÝ©YS"d\×@¥îÔ¬)²¯·¡FwjÖÙ}‰Q;5kŠ‹B|‰Q—;5kŠˆ¢|‰Q‘;5kŠ…}‰Q‹;5kŠ‚b}‰Q…;5k Â}‰Q¾;5k Œ*|‰Q¸;5k ‰Š|‰Q²;5k †ê|‰Q¬;U`ÍË—Qu5r8ü fÝá@ÕÕèòåpwÍ•ú#¯;üQ.}…°¼ÙŒRRPu5²Û} f ÝnGÕÕ(%™Íì—'ªö%F^wʤ¯Ölk Ñ÷h¡SAã-mmì—àKŒŒî”I_NÌæñ@ñø†î4€tMfÄø#£;åÐW kR‹ÏGš&3Â|‰‘Ërè+Üå•oÅâøHÓdF¤/1r¹Sr}…³&ÏŠ%A“Á¾ÄÈâNÉõtP*`Å ¿JùbЈx_bBpgÀŸ. èëƒ Ö X±Â¯Rõõ¨«‹õÛ(ñ%&(wvu¡úúp÷(¾>=”ÏQ±©R ª¬dþ*ª|‰áïÎÊJd±°G±õõAhkrT¬ð«”͆L&”“ÃðUúÃÓ99ÈdB6[¸»U߉ˆp”±b R¥êëÇJ£õéQëKL@wvu}~ŸŽÄÔw""X“±b R¥,–±Ò|ûô(÷%†Û••cÛéÓÅÓw"âL¡U,AªîÍqTŸ®ù’‚Ã99céÓ‘8úú!Ž5iK*EõæTŸ®ù’£;©Þ\À>] }ým2%U±„ªRToŽ?ÅÅš/ðwgqñ„ßM>‰ ¯¢Y“ªX‚T)ßÞBó%34wúþPöéÂêË„˜SÐÍfÁª­7÷ýh¾ô‡æNÚG> ª/¼>uddÄjµvttôööö÷÷÷õõ9N·Óér»z(999---555///77·   )))¸462o'xñE˜7/üCˆ(æÍƒ_„O?„¾ml„²² ÊcÔ·Ðét»Ý‚èËH8¾¾yóæîÝ»,X@ÿ=êtº¢¢¢ªªª+W®ðÚoîÿÉÉA••\÷0£®.TY9~=ÎöáݧK¤/ b¬Xœ$ÙÔÔtðàÁÖÖV¼E¯×,Z´(333333;;Ûd2F“Éd³Ùoß¾}õêÕîîîÎÎÎööv’$€ ³Ù¼nݺââ☘Öý54Àk¯ñ .'JK¡´rsƒ=.µÒÝ ÐØ==|³Ô×s4œRëËFPF&I²®®nÆŒ8o\\\YYYkk+I’ü q¹\ÍÍÍkÖ¬¡ÂÍÊÊjhhðz½Ìh׿Ü£Y,¨¾9AšZq:Q}=²XÑįÄr.¾,aÍŽŽŽÇï,==½¶¶ÖÞ<+‡ÃQSS3wî\\f^^^__=ŸÞwRØ‘‚\~ª›mÌ£<.¿J}ÙáeM·Û½víZ|Â1mÚ´ººº ª7çСCééé¸ã¨¨¨pú6x׿š#áéQŸët9õe'°5¯]»öØc@llìöíÛìIl8ÎíÛ·ëõz˜7oÞÏ?ÿ<öco®9’Ü}Чˬ/;¬yáÂ…)S¦àÓ… .'+—/_ž3g$''õÕWôÞ\sdh0zÔdB6›ÌúrÂeÍ'NLš4 ž{î9»ïãñbb³Ù–,Y:î“M›4G ÉDžØ²Ef}?ù„#%«5›››u:¬_¿>Øk«0ñz½«V­€XƒáÄ–-Hª_-Š°Û›7oÖ„ÌúÆÆž8q‚-³5Ï;g2™pÜ¢E€ŠŠ 0 [~`Q…¾ ÖìííMLL”7nÌêÕ« ))©¿¿_ÞH" µèK·æÈÈH~~>X,Ç#E€ìx½Þ^xòóóïß¿/o0‘Šô¥[³¼¼fÏž=<<,U„\ܽ{_ÓmÚ´IîX"é;Áš_ý5Aƒá›o¾‘0¼\ºtI¯×ëõúo¿ýVîXÔºô·¦×ëÅ÷©ÞyçÉà ÀÖ­[ñ.ïRDªÓwÜšGŽ€™3gŠt? \.¾Óõá‡Ê‹ZQ¾cÖôx<<òˆ’µ?|ø0dggË~ò®FÔ¨ï˜5?sæÌ‘xô•?£££ø|¹¡¡AîXÔ‡õ³æ“O> ï½÷ž|±æý÷߀§žzJî@Ô‡õ„POO$&&*|ìðÞ½{ñññA\»vMîXÔ„JõÕ@ss3,]ºßìW, %%%¡úúú‹øÏHZB ^¥úŽ[³¸¸˜J4wî\‚“É”‘‘±lÙ²¦¦&ü#lÙiL:•ÊrìØ±5kÖ<úè£S¦LÁ;ÊÊÊzùå—O:…<À´|ùr8}útÐÇmµÂÓOCKKЕCK <ý4X­Áæ£é+‹¸Œ|ðÁ8%5~‚¾CCCALš4idd„jZsrrøóâÅ‹].cãÌ';L™2…O–åË—ã ·ááᘘƒÁ`ã?A®­ml©‰”uOb²ÛÇ^4a6ó_˜À__YÄõ§»»›jÅs,b嫯ÁçççÇÆÆú—~éÒ%êo’$ív{ÿ™3gðSH_|ñÅž={vìØÁ\FFÆÉ“'9¢Çóî0?üpiié³Ï>›——7uêÔÁÁÁ–––íÛ· ;vláÂ…o¾ùæäÉ“ ÏŸ?öìY|û• «víofÊË!>>@%åå°u+X­`µ‚Ù ;v€Ù̉C_)Å¥a·ÛKKKN'm»¯¾PUUo½õ–¯£©ŠÅfùÆkÌž=›£bå0.ÓÊã€eSS.Êü`¡ˆ-[¶@UUWYTKI}ÔÞdb¨†“újAýõ•E\_H’üÝï~³fÍJMM¥Eé«ëîîütJJJ¦OŸýýýAeä?8BcñâÅøü>/éa{æŸSúŸ“©½ÉÄà†Ó¶ã}@úŠ!®/uuuÿøÇ?bbbŽ;–@û–ÒWwãÆ À·‰øCD||<à©âqÿþ}üǬY³ð8ô+W®Ð“rˆ”’ë׋¦„¬_))ôìÇ‚¾¢Š{ñâÅ7À¾}û üPúênÞ¼ ¸]åÏÀÀÀõë×!øæ6Xð¿ÿýïñiiiðË/¿Œ' ÔrDH“‰ño8)˜~‡ôOÜ{÷î•––ŽŒŒ”””üñdL3®ïäÉ“€vÁË}:2::úꫯâÇãt!äõz:d4àí·ß¦æ¤`S&%%!ÄtN©}&žƒúë+—¸$I–––@VVÖÐÐo0¾EQúðð•Á`É8„Ðýû÷¯_¿ÞÞÞ~àÀ‹/ÀæÍ›_zé%Ž\^¯whhˆí[£ÑHþïÿûÙgŸ9Žk×®ýë_ÿº~ýúoûÛ]»v=óÌ3T|vâv:Cä‹\Å“££H_iÄ­©©illŒmllÄO32¦¯Û qqq@›(pè+55õ£>â˜=ɳmÛ6Z.Ú`ĬY³þö·¿ýïÿóMãr¹ !.Nk/ù´qF#M_YĽpὪ­­õwšo«9¦oBB€³gϲÅŽ5Μ9sòäÉšššÒÒR\׎ú,îªuèQÝ¿ÿ—_~ɯ¡a6›§M›íííx Ѥ&ø&…¶6hkc¸w7055"G*55ðàîÃ8ìÇÎ__‘Äå˜&Â¥¯.77¾ûî;ž9gΜ¹wï^ü÷ªU«l6[P;j‹ÝnÇ[pè¬'Ll"íÛ‡˜‘J‚ÃûöMØÂQ! (}ÅwÞ¼ywÙÁifÏžÿÝ¿ÿ¸¾gΜ€¢¢"ßF˜{èËëõ.\¸'X¹reøm>‡_Ùeddà-¸‡:yòdàÌ´.>Î8}Ï2ùÍ?ò×W9â2Eé`R[‰===Ô],Æõ¾Bˆ~ttÔ#U‰7lØ€´Iq‚NŠcË"†¸lЊòÕB………ÐÜÜLe=BhÏž=8ÍôéÓïܹ~ô3fÌØ°aéS§nݺ5<<|éÒ¥òòr‚ ࡇ‹…ž:u æÏŸÏ¿Ø1°AUÝpVWeJ š¾²ˆË­(_}ŠcÅŠT>ÑŽŽâÕsÀb±ÐÆ«BˆXxøá‡;::pš+VÀ®]»ø;––3*Pƒ§é+‹¸lЊòÕ—ù±5>Ñ#„¾ÿþ{j&Û|fô{÷î]¾|ù¯ýk<í%11±¨¨è¯ý+u¿U{l-4húÊ".¾EÑôÕö Ô¨¯¶DBT F}µ…e¢5ê«-Ç-¨N_mÃhAuújK¿FêÒW[0;ºP‘¾Úk¢ 髽œ%êP‹¾Ú+­¢Uè«ìr¾(N#”¯¯²_ŸÊùzM0Q¸¾Ê~é´†È(YßÖD ~•»† (VßÀÖD¹Ýîµk×âY½Ó¦M«««ð®ŒÇã9tè¾O¥×ë+**œN§P…kðA™úò²&¦££ßé€ôôôÚÚÚ0k˜Ãᨩ©¡žÌËËëëë §@pPš¾AX!D’d]]ÝŒ3ðÎâââÊÊÊZ[[ƒªd.—«¹¹yÍš5111¸œ¬¬,¼nPÁhŽ¢ô%ï5[Î/ÀIDAT¥¹)H’ljj:xð`kk+Þ¢×ë -Z”™™™™™™m2™ŒF£Éd²Ùlƒƒƒ·oß¾zõjwwwggg{{;~6™ ³Ù¼nݺââbê04dG!ú†bMŠ[·n>|¸¥¥¥½½9:î‰'žX²dIII Ï%ï5dA^}ò&ÅÈȈÕjíèèèíííïïïëës:n·Ûår%$$$''§¥¥¥¦¦æåååææ$%%…¿S ÉEßÿ]Žy,Þo‡(IEND®B`‚quagga-0.99.22.4/doc/fig_topologies_full.txt0000644000175000017500000000010612000052240015544 00000000000000(RF1)--(RF2) | \ / | | \/ | | /\ | | / \ | (RF3)--(RF4) quagga-0.99.22.4/doc/fig_topologies_rs.dia0000644000175000017500000004162512000052240015157 00000000000000 #A4# #RS# #RF2# #RF4# #RF3# #RF1# quagga-0.99.22.4/doc/fig_topologies_rs.png0000644000175000017500000002341212000052240015200 00000000000000‰PNG  IHDRÞÞÝ)àsBITÛáOà pHYsÐй‹çŸ IDATxœíiTTGÚÇÿ½ÙȦ²$€‚,¢ Ñ F='NŒÑ9ˆÄd—à”1ñ&2‰Y4=&šxrBDÜ2\"&Îà‚‘Œ¢Aƒ¢, .¸°JÓtßz?v7M¯ÐÛí¾¿ÓºëÖ­ûÜú?u»n­ûì”)SÂÃÃ{|usc]}{âš Ãì߿˖-ùùù4D DGGOœ81((((((,,ÌÉÉI,;99566Þ¿ÿîÝ»7nÜ()))...,,dÇ›0aBrrr||¼H$êñ=p˜[Ñ—Ã0YYY>>>ô\ggç™3gæçç3 cx"‰$777))Ianppð®]»är¹QÆp˜›Ò××,**5j½X@@@fffkk«QS£µµ5##cèС4ÍÈÈÈÊÊÊÞ$ÈÑlM_ƒ\S*•Ο?ŸÇãðððÈÊÊ2ªéF&“eggÐ?ŽeË–µµµ™*qC°M}õ»fEEÅÈ‘#ôéÓ'--­—%Immmiii@DDÄ­[·ÌqŽîج¾z\óüùóýúõ£Õ…óçÏ›ÈN­\¹r%44€——×É“'Í}9[ÖW—kæååõíÛÀ‹/¾ØÒÒbR#µÒØØ8eÊ|>ÿÀ–¹¨cbãújuÍÜÜ\>Ÿ`áÂ…~w–ËåsçÎ¥1yyy–¼´ã`ûújvÍÓ§O;99Q»Íf¡–-[@(rÿì&‡újpÍòòrwwwëÚM™7oOOϪª*ëZbO°E_u×looŠŠ'“É,a värùÔ©SDEE=zôÈºÆØ,ÒWÝ5—.] $$¤¹¹ÙRêâáÇô.55ÕÚ¶Ø,Ò·‹kž={–Çã …ÂsçÎYÐ<=\¾|Y ‚_~ùÅÚ¶°vé«tM¹\Nû©V¬Xaqóôðî»ïÒž.öR8¬ÓWéšÛ¶màïïo¦þ€Þ ‘HhO×öíÛ­m [a¾®)“É dËÚçää ³zå°QßN×Ü·o€ÐÐP›™ÖÑÑAëË»ví²¶-ìƒúvºæsÏ=`Ó¦MÖ³M?ß|ó €ñãÇ[ÛöÁF}A)++àîînãm‡MMM...<¯¢¢ÂÚ¶° –êË›› `Ú´i´³ßfqssKHH „ìܹÓÚ¶° ¶êK‰‰‰››«ð_³Äbq```BB¾}ûtT\ ´¦_¿~ÝÏíèè¸páÂÆ_}õUÕC‡k¢‚ê¨ékq›ššrrrf̘ܧO@øÆo\¼xQ5eU}ÑÐÐÀãñúöíÛÞÞ®ˆaàD¸É“'K$SYOùøãŸþyÕ8ªš››E"‘P(lll4TǦ»¾–·¶¶ÖÕÕUc>Ÿ¿yófEʪú i|TTTŸ>}ºŸyùòeÅw†aZZZªªªŽ?Ng!ýðÃkÖ¬ù裴7xðàC‡é°žŽËR°jÕ*¹\. cbbJKK›››Õ⻺ºÆÄÄœ9sæÔ©S´û•C7:ôµ˜¸R©´¥¥å©§žJLL¤Ó2[[[9²téÒ†††E‹=ýôÓ£GFW}‘žž`ñâŪÅBQ°´•Ž{÷Ò!!!: Vxx¸œÕ«Wÿ÷¿ÿ¥mÂÚlxçw¤§§•²ÃÒ]_Ë‹ûðáÃcÇŽuïÉ;xð MjÚ´iŠ@…¾Â’’tvˆá$$$x{{×××WUUu¢nÒÒÒôÆ¡3ôè['‡^z ¯ÉÅíß¿ÿ¤I“º‡ÿõ¯uwwojj:sæŒ"P¡/ÿöíÛh7‘áðx}ºŽ³äryCCƒ¶£b±¸ÀÔt©Tj쉎‰!úZE\¹\N_ÿE"ÑòåËáJ}¨ ”ÒÛôåçç·cÇ£'uŸNyï½÷t¼Öi{‘”H$ô {;ttºëk âBÞÿ}3##C5\¡¯6>Éd2C®§`÷îÝtÄ€å¡[a9ºÓ}- îúõëi«Ö§Ÿ~úüCõRßàà`ׯ_Wõ\EÁzØ:@xx¸î©Šhº‹Ž´=5+++õ8e‡¢»¾Ö—a˜?þŸÏW{^RúbìØ± Tks †a}0)))f²^· §OŸÝ㔊îúZQ\†ah‹º‹‹Ë‘#G4ÆQè˧ïê´±@/</33“VT7nÜxâÄ CÎ2-´ES±4‡n ××ÜâBÞzë­/¾øÂÕÕõÇ|饗4FSèË1b€ .xÿuëÖÑïsçÎmll4…ÙF@MçVÚ6£ô5«¸|ðAff&€Ý»wÇÆÆj‹¦Ð—ÿç?ÿÀÿþ÷?ï‘””4nÜ87oÞ\¼xqoM6’¢¢"<Îq½«¯™ÄÝ·oßêÕ«,X°€.Ç¥ ¥¾ºÅi«4”••)z±4®÷E™¼®É Š3ƒâ´brqkkk @ ܾ}[GÌ.ƒâúõë]TTtôèÑiÓ¦XÂÂÂ>þøcÚRº`Á‚1cƨö5õÚ¦E¡mÅj±±±tÕ½ô@_“‹»~ýú‡4hÐñãÇ5ÆILLpòäI¥¾„5kÖ˜3gŽÂyõ,BHGG]=@\\œZ - 7ö©IW­ÕÁË/¿ à“O>1*YGM_Ë‹ûÆoèu_sΜ9 }5O[3ÄzBÈÅ‹δuëÖÞXOÑëšÎÎÎÜ´5cQÓ×òâèšjÓָɾõå–Hpب/·°ŒCÀF}¹å¸ÖéË-bè(°N_néW‚]úr f;,Ò—ÛfÀ±`‘¾Üæ,[ôå¶´rDX¡¯mo(æmÛfÉK;¹ÙÙ|ÏÊúö`#@Šõ·×œ4‰ˆÅ$5•Ô×[æêA}=IM%bqÞäɬÜ>•båM‰7l ˆ»;YµŠX*ûì––²jqwïÌÕ غé4Åš[¹=Ú™‰ôããC22ˆTjì©”ddŸ.ùyô(±®¾:Ñïš„©T:þ|ÀÃÃ#++Ë„½22™,;;›öS ‚eË–µµµu«¨è’•ôJvï&\·0 Ù½›„†jÈÉÇc ­¦¯N rMJQQíé™™ÙËÖÚÚš‘‘¡˜YYYÙ%†LFÄb y ‘#É?öæêÁ?’‘#5g XLº¶kZA_áš„†a²²²|||{gΜ™ŸŸoT!“H$¹¹¹III"‘ˆ¦LWÂÕ{øpÍ9K?ù 1 ‰•œ?Oþò]Y7|x÷“¬ ¯vxÄॹ0 ³ÿþ-[¶äççÓ@M×B srr‹ÅNNN÷ïß¿{÷î7JJJŠ‹‹ é¼7a„äääøøxÅm¨“€tYÃãáÕW±jBBŒ½û¤¼+V`ÏèVvútì߯ñˆEõÕQެÆ;wV¯^=vìXZM1>Ÿ?zôèôôôk×®é¿FZ𮢝øˆDdáBRSÓ›Ûa=55dáB"”ciizÓ³„¾ÚéÉS³;íííEEEåååUUU•••mmmR©T"‘¸¹¹yyy 8ÐÏÏ/22rĈÑÑÑžžž†&½m ìêŠ%K°t)m¾eS>ÿ6 ¥ÅÐSrr`À”ŠõÕŽi\ÓŒüü3FևǃŸÂÆðpŒ‡gž±ˆq6Cq1NBY®_GYîÜÑóoàìYh_Bðy×|ðÚŠ`d$Þ{aaˆˆ€³³eͲm=ÂÕ«¸~k×â×_5ǹ–5Ë8øú£Xx{k>ôë¯ 1r$ç—ê8;cäH…ZýÒÛÛÆý,pMj+o©®$‘œŒ[·,l;¸u ÉÉÊŸjËo°a13¶¹¦·7„XÜùóÁ$&âñ40 ñàAçO±vùóá\Ó4„…)¿ðbc±zµ2äÄ lØ`y£lš  º:æêÕˆÅ(CT³ÔféMË“…8x°³).(ˆÐåÎär2qb—>·K—¬m¥ÍpéR—Þ݉ í†io'AAZÛJý°Á5¯^íÌÐ;•·n¥ú1lЀÓÖFþô'e¶xxÕ1>;wv†_½j= … ®ÙÞN„BIÔ:a÷îíÒ½¡sùqG!%¥KžìÝÛå¨\N"#‰PHTÖRµYØàš„ÐP:¸PÄD¥ <9vÌâ–ÙÇŽO™!‰‰â=JBC-nYO`‰k~þ¹æð¦&¬Ã×WëTÿÛ|ÖYm7R_O|}•YLšš4ÇÔ–™6K\SÇxª³g‰P¨”$>^CœæfâãClo­£im%>>DãêññÊL ÉÙ³Z±ÕÅâÔ`Cã¾v;ccñÏ*ææâÛoÕã¬_»wqã†Yl³$7nàî]¬_¯þí·ÈÍUþüç?uõëÈL›ÂÚeÃtt˜å3ÃÕ•¨nWWGÜÜ@ö챞‰&bÏ77RW§ ¼~¸º*o?&†ttXÏD“Á’¤¡;wÂÕµógK fφbWÆO?Es3”•YÇ<Bo¡¹Ÿ~Ú"“aölåX8WWìÜ }û4³»pM!!øòKåÏ¢"¬\ UUøúëÎ@»qM_ª*X¹EEÊ_~i?£ý­ýØ6)ª¯),$³f)CF²¶}½fÔ(åíÌšE ‰@ çµØüxM£¸w‘‘¸s§ó§¿?îÜQþpw‡Å·-41ýú¡©©ó;Ÿ??åÀ+??üú+¼¼¬ešÉ±—?tŠ—¶n…b"Ë­[]%55¡¦Æ*v™†š¥_`¥_òxغ՞üö暆G|¼Ö£¬®nê0>>Ç[ÐKÀæW¹ÖÖΩ0Š91eezæm••a ™grt¸æ8p®®WΑ¢_\\,h¢)a³k64 #99Êv"½ØëS“ÒÒ‚ @÷— ‘˜ˆ?f¯k²ù}à@de¡¤ññ0p¢ôõëf¶Éœh<‡øx”” + šÙ&3ÂfפDDàÀœ=‹ñãõG¶ï§&€ñãqö,@D„ù 2/öÕxtô(ÒÒPR¢5‚PˆÖVôécA›L„T ]U—#ðÙgxé% Úd^ØÿÔT套pñ"¶oÇàÁš#Èd(/·¨I¦¢¼\«_ŒíÛqñ¢=ù%ìÍ5ðù˜=×®aÃÍí|,­nj4ÛË 6àÚ5̞͚ñDco÷Ó‰XŒÔTTT`Å õWT–V7ÕÌvqÁЍ¨@jªrê³}a§®IqwÇÊ•(/ÇÂ…P,¢Çv׉°p!Ê˱r¥}¯:f×®IññÁæÍ(-Å«¯‚Çc±kÒ•DKK±y3¯ÎjÇØ×º^.\à=^šuóç1r¤µ­°暀Q«˜Úަ›;*{»dfoqê P×ä`'œkrØ(œkrØ(œkrØ(œkrØ(œkrØ(ÚxdC‡-ÓÒu$‹}||FõÚk¯ÅÇÇóµ­øã?rrr ÊÊÊîÝ»×ÑÑ!‹ àïïñÌ3Ï<ÿüóO=õ”Ùn‚ÍXs¦±50ü®Ã [ð|òäɉDc _~ùe}cCcbbLh³=Á=5õsùòeÅw†aZZZªªªŽ?N·ýá‡Ö¬YóÑG©uàÀÔÔTB¡011ñÅ_ ‰D---·oß¾zõêÙ³gOŸ>mÑ;aÖ.–Æð»V<5µEØ»w/ÒýhLL =š››«-…G;w΄6ÛÚ‡nÈ]+êšÚ"Bž|òÉúúz@ ë6ÝÉÉ©½½Ý××÷öíÛ½ìi4Üf{‚{Cï9<ÏÅÅ€““S÷£tãe¹\ni³ìÎ5{N]]]uu5€‘šÆªÑÀºººM›6YÚ2»€sÍ"“ÉRSSé£1%%¥{„´´4ú%%%eúôé………ŽöÜ[¬Yѵ†ßu÷× úz^ZZš••õôÓOÓ£K–,aFc _|ñ…j-3 àí·ßþñÇÛÜÅA•²¶–¦®© ??¿;vhóKÊÏ?ÿ<¡Û*Kýúõ›7oÞ… Ln³=áx7l:×ìʶmÛhxxxx«‘¾Ü¾}{Ó¦M±*ÛSשîÐ;›í Ç»aã]S-œa˜©S§ÒC)=Ý}ðçŸ:t(MdÁ‚¦²Ùžp¼îµkBnÞ¼éææFþôÓO=³¤²²’¾$ùúúêŽé˜®É5õÿuëÖÑïsçÎmìÑñAAAƒP[[k:ÓìÎ5{HRRÒ¸qãܼysñâÅ=HaêÓ^öµ»©à\³‡ðùü¬¬,ÚE¹mÛ¶\Õ}ø/¼ðÂÞ½{ÛÚÚ´¥°cÇŽ˜4i’YMe)Üð­èÞ`íڵ˗/àíí}åÊ•'žxBíBÎÎÎãÇ6l˜¯¯¯‹‹‹L&ûý÷ß:´}ûvBˆ››[qqqˆÎ}¨sx‡ÃU® ¿k½ƒâ!QQQ4Z\\œjó»···ÞÌ äÅiƒ{jjŧ&€K—.5ŠŽ0Úºukbb" gæÊ•+………ÅÅÅ¥¥¥üñǽ{÷ÚÛÛE"‘OTTT\\Ük¯½Ö·o_ÚlOp®ÉØhsïá^ƒ8lÎ59lÎ59lÎ59lÎ59lÎ59lÎ59l]½Ã1— föÔûLùóñö(DD€ÕŽx<õ†wÕüì3œ,Z¤ùôæf’“cVMK\sî\²j•†ð¼¼Î?kú™=[k ÇŽ™Ï:‹¢ãFfÏVfGòò4ÄYµŠÌk>ëLKzƒž}ee¨¨€‡‡2ðÎDFâ޽Ο!!(.ÆãÕÿ‘æf<ó ÊË;zyá×_»Œò|ðC† <œ3àØÐxD®^EC¯ì ƒÙ³•~)á»ïÚ/¸¹á»ï uþ¼w³g+gžƒY¯^+žGÖ~l@uu矔‹ ©©é üì³.U«5k¬j¢-±fM—œùì³ÎðšââÒX]mU ‚ ®yì˜2£ß~›BÎ#"‘2pâD{xû6r9™8Q™9"¡kr¿ý¶2 5o6ü¡—–*¿ó ~û 3g¢££3ÄÛ»Kí S¬$ßÑ™3ñÛoøæeÕ,µUØ èÕ«Êïí툋SŽåñÍÊihfÅ×ÙÙʱ,ˆ‹ë2ŒU5Km6¸¦ZW¹½hoÉÑ…©S±h‘ò§Úpwî©i´å£¿?ââÐÔdYkXBSââ´ŽOeƒkÚ|»¦Žù× ž|Æ!"B9÷àÉ'-bœÍP[«œ‚rõ*JKõ¯›`óóñM37¨½½½   ¨¨¨¼¼¼ªªª²²²­­M*•J$777//¯úùùEFFŽ1"::ÚÓÓÓФ )ßµµ¨­Åÿ cÆ =Ýá\óÚ5¬XÂB#N)-5Ü5ͨ¯zózçÎÕ«W;Ö¨å*ù|þèÑ£ÓÓÓ¯]»¦ÿ7vi¥Óñ‰Š²‡ao½áÈehvmܨ7=K諞ü¡3 ³ÿþ-[¶äççÓ@=qâÄ      °°0'''±XìääÔØØxÿþý»wïÞ¸q£¤¤¤¸¸¸°°a<o„ ÉÉÉñññ"E†ÿø¾þZAC‡båJ¼ü2»çW˜B°o>ü׮鉙œŒÌLG,ª¯Î{1†a²²²|||è¹ÎÎÎ3gÎÌÏÏgŒg%‘Hrss“’’æïÚµK®±Ù|Ü8]Eð`²u+‘ÉŒº ûG&#[·’ÁƒueݸqÝϳ‚¾Ú1Â5‹ŠŠFE/™™ÙÚÚjÔÅÔhmmÍÈÈ:t(M322²²²R=’··æœõõ%›6‘ööÞ`ç´·“M›ˆ¯¯æ ôöV‹n}µckJ¥ÒùóçÓ ‡‡‡GVV–QÅH72™,;;; €þq,[¶¬M1 ¶®NCžzz’µkIïrÍhm%k×OO 9YWG£XM_èwÍŠŠŠ‘#GèÓ§OZZZ/K’6ÚÚÚÒÒÒ€ˆˆˆ[·nBHAA—¬ts#~HÌa€ÓÐ@>ü¸¹uÉÏ‚b]}u¢Ç5ÏŸ?߯_?Z]8þ¼‰ìÔÊ•+WBCCxyyÿÀK/‘ˆ$' ‡¡ÜºE’“‰H”7uª•õ=p@GL­®™››Ëçó,\¸ÐØw«^"—ËçÎ  P˜·u«%/í8änÙÂçñ¬¬oŸ>yg‰B´¹æéÓ§œœ¨Ýf³PË–-  õ>ù9Œ…újpÍòòrwwwëÚM™7oOOÏ*;˜Bn3°E_u×looŠŠ'³vS¶\.Ÿ:u*€¨¨¨GY×û€Eúª»æÒ¥K„„„4k›÷mY>|HßéRSS­m‹=À"}»¸æÙ³gy<žP(**ª¦mä._¾¬øÎ0LKKKUUÕñãÇé,¤~øaÍš5}ô‘6ã|èÐ!ÖóU–Ñòõõ1cƤI“"##û÷ïÿþý£G¦¥¥544|ÿý÷ãÆ{ë­·\]]cbbΜ9sêÔ©©Ü’2 C_Kn ÃA¡IDATŠ«FKKËŒ3ÚÚÚÔÂUõEzz:€Å‹«z´¢`isù½{÷Ò!!!: –¢4‚ÆËýû÷Ó¤&L˜@CÞyçéé醧ìÈt××*âªÂ0Ì믿 00ÐÏÏO-)…¾ü’’tvˆá$$$x{{¨ªª2êDЉ#jLž<™~©{¼Ý9¡Gß:9ôÒ}Í!®*YYYß}÷H$úþûïݺ-$­Ð—ûömÚ¶ŒÕÇsqq@G¤šGÑ/ô 5ýšÞ%8=Ð׬â^ºt)%%ÀçŸÝ=‚B_þ;wøé]òª+uuuÕÕÕ0þqk,»ví¢_þþ÷¿Ó/P__oÖëÚ =Ð×|â655͘1£½½=!!áí·ßÖG©¯««+µ^ÝÕ‘ŽŽŽ×^{FØ·oŸ9ª#„¹\ž-‹,_¾\Ñ~DÒÓÓ³Ç);Ýõµ–¸ Ã̘1@pppÃãÛÔÕ¤ú éò4B¡ž%ã!=ª®®.,,ܼyó¥K—,Y²dúôé:Î’Ëå ÚŽŠÅbµFàßÿýßÿþwkkkEEÅO?ýT]]=f̘O>ùäùçŸWÄ¡µ©TªÛ`Š!úZFÜŒŒŒ½{÷öéÓgïÞ½t†±F”ú:;;P(¥·éËÏÏoÇŽ:FOê>òÞ{ï©¥Ö¸~ýú{÷î©Æ‘H$ôŒ*²Kw}­"îùóçiëUf×Ý]»?5úòiã“L&3äz vïÞ=kÖ,£Ö¶3„˜˜˜ãÇ:t(##cÆŒ·oßþ¿ÿû¿   ={ö(â477ÐØ ËÑèkrqf̘!•Jÿö·¿-X°@wd¥¾ÁÁÁ®_¿ÞÝ—<ì Ž <<\÷ˆTE4 ·FJKKé‹9ŸÏ?sæ ¬¬¬Ô›”‡îúZX\†ahÅ ,,¬©©Iíh÷§¦B_Œ;@AAA÷Э¦Ì0Œ¢&%%ÅTÖëà?ÿùMjòäÉ4äôéÓ¢íf;T3Ó]_ ‹ûÛo¿øp0oÞ<…¾|ú®N ôÂãñ233iEuãÆ'Nœ0üª=c„  ¯M[4KãqèÆp}Í$.£º¡(ôå1À…  <ÓßßÝã½"çÎÛØØhÔ……Çãõïß@KK ¡¦8FÃ(}Í!nDDÄCíÐ8!!!ôçÆ•ú?~ÀèÑ£Uº›¾ärù¸qãh„7Þx£÷Ï|´¶¶Ò7žÁƒÓúuèС^¦ì t××vÄÕ˜”B_=ƒâ´¥XVV¦èÅÒ¸ÞW¬ïèèè¨(Ä‹-"Ü 8ãÑ1(NÛ)æWjI©ê«g(±ŽD׬YCãx{{×ÖÖöÞzŸE‹>|¸¦¦¦¹¹ùòåËK—.¥M  ‹…rC‰{€¶¡Ä:N1¹¸ÚPKªËPb…sæÌQœ`ˆõtõqqqj-´=°Zðõõ-**¢qæÌ™à“O>1>>ôbÎÎÎ3gÎÌÏÏ7ªI$’ÜÜܤ¤$‘HDÓ ¦+áe ‡É±)}yÄॹ0 ³ÿþ-[¶äççÓ@=qâÄ      °°0'''±XìääÔØØxÿþý»wïÞ¸q£¤¤¤¸¸¸°°ÎMæñx&LHNNŽW܇ձ}{âš jjjrrrŽ=ZXXhx:|>ÿÙgŸ2eJBB7Ü–±®¾½rMíííEEEåååUUU•••mmmR©T"‘¸¹¹yyy 8ÐÏÏ/22rĈÑÑÑžžž½¿(‡Å°Š¾ÿTÛ@8T5IEND®B`‚quagga-0.99.22.4/doc/fig_topologies_rs.txt0000644000175000017500000000006512000052240015232 00000000000000(RF1) (RF2) \ / [RS] / \ (RF3) (RF4) quagga-0.99.22.4/doc/filter.texi0000644000175000017500000001431212000052240013134 00000000000000@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-0.99.22.4/doc/install.texi0000644000175000017500000002326312211704467013345 00000000000000@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 --enable-guile Turn on compilation of the zebra-guile interpreter. You will need the guile library to make this. zebra-guile implementation is not yet finished. So this option is only useful for zebra-guile developers. @item --disable-ipv6 Turn off IPv6 related features and daemons. 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 (internet-draft) this requires support for Opaque LSAs. @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 --disable-tests Do not build tests. Test programs are built by default, but not ran or installed. They can be excluded from build with this option, which will minimally decrease compile time and overhead. They can always be built and executed at a later time by running @command{make check} in the @file{tests/} subdirectory, even if they're excluded from build. @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 @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-0.99.22.4/doc/ipv6.texi0000644000175000017500000001536212177450262012566 00000000000000@node IPv6 Support @chapter IPv6 Support Quagga fully supports IPv6 routing. As described so far, Quagga supports RIPng, OSPFv3, Babel 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-0.99.22.4/doc/isisd.80000644000175000017500000000522412000052240012162 00000000000000.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-0.99.22.4/doc/kernel.texi0000644000175000017500000000343212000052240013130 00000000000000@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-0.99.22.4/doc/main.texi0000644000175000017500000002540412177450262012624 00000000000000@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 * 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 @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 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.255.255.0 10.0.0.2 ip route 10.0.0.0 255.255.255.0 ppp0 ip route 10.0.0.0 255.255.255.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 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 @example 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. @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 format of the messages exchanged with the FPM is defined by the file @file{fpm/fpm.h} in the quagga tree. 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-0.99.22.4/doc/mdate-sh0000755000175000017500000001363712070614057012436 00000000000000#!/bin/sh # Get modification time of a file or directory and pretty-print it. scriptversion=2010-08-21.06; # UTC # Copyright (C) 1995-2012 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-0.99.22.4/doc/mpls/0000755000175000017500000000000012211704577012033 500000000000000quagga-0.99.22.4/doc/mpls/ChangeLog.opaque.txt0000644000175000017500000002000012000052240015577 00000000000000----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- 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-0.99.22.4/doc/mpls/cli_summary.txt0000644000175000017500000000525512000052240015022 00000000000000Summary 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-0.99.22.4/doc/mpls/opaque_lsa.txt0000644000175000017500000005505412000052240014631 000000000000001. 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-0.99.22.4/doc/mpls/ospfd.conf0000644000175000017500000000305412000052240013712 00000000000000! ! 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 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-0.99.22.4/doc/ospf6d.80000644000175000017500000000516312000052240012252 00000000000000.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-0.99.22.4/doc/ospf6d.texi0000644000175000017500000000565712000052240013064 00000000000000@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 @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 is 1. @end deffn @deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {} Sets interface's Hello Interval. Default 40 @end deffn @deffn {Interface Command} {ipv6 ospf6 dead-interval DEADINTERVAL} {} Sets interface's Router Dead Interval. Default value is 40. @end deffn @deffn {Interface Command} {ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL} {} Sets interface's Rxmt Interval. Default value is 5. @end deffn @deffn {Interface Command} {ipv6 ospf6 priority PRIORITY} {} Sets interface's Router Priority. Default value is 1. @end deffn @deffn {Interface Command} {ipv6 ospf6 transmit-delay TRANSMITDELAY} {} Sets interface's Inf-Trans-Delay. Default value is 1. @end deffn @node Redistribute routes to OSPF6 @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-0.99.22.4/doc/ospfclient.80000644000175000017500000000166612177450262013250 00000000000000.\" This file was originally generated by help2man 1.36. .TH OSPFCLIENT "1" "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-0.99.22.4/doc/ospfd.80000644000175000017500000000524412000052240012164 00000000000000.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-0.99.22.4/doc/ospfd.texi0000644000175000017500000007351112101110036012770 00000000000000@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 * Configuring ospfd:: * OSPF router:: * OSPF area:: * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: * Debugging OSPF:: * OSPF Configuration Examples:: @end menu @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>}} {} 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. @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 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} {} @end deffn @deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {} @end deffn @deffn {Command} {show ip ospf database max-age} {} @end deffn @deffn {Command} {show ip ospf database self-originate} {} @end deffn @deffn {Command} {show ip ospf route} {} Show the OSPF routing table, as determined by the most recent SPF calculation. @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]} {} @end deffn @deffn {Command} {debug ospf ism} {} @deffnx {Command} {debug ospf ism (status|events|timers)} {} @deffnx {Command} {no debug ospf ism} {} @deffnx {Command} {no debug ospf ism (status|events|timers)} {} @end deffn @deffn {Command} {debug ospf nsm} {} @deffnx {Command} {debug ospf nsm (status|events|timers)} {} @deffnx {Command} {no debug ospf nsm} {} @deffnx {Command} {no debug ospf nsm (status|events|timers)} {} @end deffn @deffn {Command} {debug ospf lsa} {} @deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {} @deffnx {Command} {no debug ospf lsa} {} @deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {} @end deffn @deffn {Command} {debug ospf zebra} {} @deffnx {Command} {debug ospf zebra (interface|redistribute)} {} @deffnx {Command} {no debug ospf zebra} {} @deffnx {Command} {no debug ospf zebra (interface|redistribute)} {} @end deffn @deffn {Command} {show debugging ospf} {} @end deffn @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 quagga-0.99.22.4/doc/overview.texi0000644000175000017500000002770512177450262013554 00000000000000@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-0.99.22.4/doc/protocol.texi0000644000175000017500000000711712000052240013515 00000000000000@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. Two versions of the header are in use. Version 0 is implicitely versioned. Version 1 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 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. We do not anticipate there will be further versions of the header for the foreseeable future, as the command field in version 1 is wide enough to allow for future extensions to done compatibly through seperate commands. 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. Version 1 will be used as of Quagga 1.0. @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) @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 Header Field Definitions @table @samp @item Length Total packet length including this header. The minimum length is 3 bytes for version 0 messages and 6 bytes for version 1 messages. @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 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-0.99.22.4/doc/quagga.info0000644000175000017500000001766412211704577013140 00000000000000This is quagga.info, produced by makeinfo version 4.13 from quagga.texi. {No value for `COPYRIGHT_STR'} 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 * {No value for `PACKAGE_NAME'}: (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 0.99.22.4, last updated 4 August 2013 of `The Quagga Manual', for {No value for `PACKAGE_NAME'} Version 0.99.22.4. {No value for `COPYRIGHT_STR'} 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: 1953 quagga.info-2: 247700  Tag Table: (Indirect) Node: Top1953 Node: Overview3330 Node: About Quagga4751 Node: System Architecture7037 Node: Supported Platforms9727 Node: Supported RFCs10976 Node: How to get Quagga13158 Node: Mailing List13582 Node: Bug Reports14029 Node: Installation14907 Node: Configure the Software15341 Node: The Configure script and its options15589 Node: Least-Privilege support19168 Node: Linux notes20904 Ref: Linux notes-Footnote-122762 Node: Build the Software22828 Node: Install the Software23376 Node: Basic commands24860 Node: Config Commands25635 Node: Basic Config Commands26576 Node: Sample Config File32650 Node: Terminal Mode Commands33420 Node: Common Invocation Options34545 Node: Virtual Terminal Interfaces36003 Node: VTY Overview36514 Node: VTY Modes37772 Node: VTY View Mode38222 Node: VTY Enable Mode38472 Node: VTY Other Modes38750 Node: VTY CLI Commands38926 Node: CLI Movement Commands39386 Node: CLI Editing Commands39909 Node: CLI Advanced Commands40497 Node: Zebra41263 Node: Invoking zebra41907 Node: Interface Commands42438 Node: Static Route Commands44003 Node: zebra Route Filtering47269 Node: zebra FIB push interface48424 Node: zebra Terminal Mode Commands50920 Node: RIP52325 Node: Starting and Stopping ripd53286 Node: RIP netmask54723 Node: RIP Configuration55822 Node: RIP Version Control58822 Node: How to Announce RIP route61004 Node: Filtering RIP Routes63569 Node: RIP Metric Manipulation65036 Node: RIP distance65949 Node: RIP route-map66764 Node: RIP Authentication69309 Node: RIP Timers71552 Node: Show RIP Information72840 Node: RIP Debug Commands74213 Node: RIPng75209 Node: Invoking ripngd75529 Node: ripngd Configuration75778 Node: ripngd Terminal Mode Commands76529 Node: ripngd Filtering Commands76893 Node: OSPFv277402 Node: Configuring ospfd78053 Node: OSPF router78601 Ref: ospf router-id79148 Ref: OSPF passive-interface82359 Ref: OSPF auto-cost reference-bandwidth86783 Node: OSPF area88455 Ref: OSPF virtual-link90786 Ref: area authentication message-digest94497 Node: OSPF interface94913 Ref: ip ospf authentication message-digest95563 Ref: ip ospf message-digest-key96545 Ref: ip ospf dead-interval minimal97354 Node: Redistribute routes to OSPF99759 Ref: OSPF redistribute100745 Ref: ospf distribute-list102585 Node: Showing OSPF information103038 Ref: show ip ospf103249 Node: Debugging OSPF104554 Node: OSPF Configuration Examples105629 Node: OSPFv3106999 Node: OSPF6 router107354 Node: OSPF6 area107708 Node: OSPF6 interface107886 Node: Redistribute routes to OSPF6108763 Node: Showing OSPF6 information109079 Node: OSPF6 Configuration Examples109936 Node: Babel110357 Node: Configuring babeld111169 Node: Babel configuration111625 Node: Babel redistribution113555 Node: Show Babel information113875 Node: Babel debugging commands114311 Node: BGP114803 Node: Starting BGP115726 Node: BGP router116329 Node: BGP distance117604 Node: BGP decision process118044 Node: BGP route flap dampening118561 Node: BGP network119277 Node: BGP route119469 Node: Route Aggregation120023 Node: Redistribute to BGP120594 Node: BGP Peer121123 Node: Defining Peer121312 Node: BGP Peer commands121927 Node: Peer filtering125911 Node: BGP Peer Group126421 Node: BGP Address Family126736 Node: Autonomous System126892 Node: AS Path Regular Expression127771 Node: Display BGP Routes by AS Path129020 Node: AS Path Access List129462 Node: Using AS Path in Route Map129931 Node: Private AS Numbers130214 Node: BGP Communities Attribute130374 Node: BGP Community Lists132837 Node: Numbered BGP Community Lists135493 Node: BGP Community in Route Map137082 Node: Display BGP Routes by Community139027 Node: Using BGP Communities Attribute140198 Node: BGP Extended Communities Attribute143768 Node: BGP Extended Community Lists145542 Node: BGP Extended Communities in Route Map147419 Node: Displaying BGP routes147880 Node: Show IP BGP148119 Node: More Show IP BGP148821 Node: Capability Negotiation150143 Node: Route Reflector153617 Node: Route Server153898 Node: Multiple instance154966 Node: BGP instance and view156813 Node: Routing policy158195 Node: Viewing the view158965 Node: How to set up a 6-Bone connection159252 Node: Dump BGP packets and table160626 Node: BGP Configuration Examples161210 Node: Configuring Quagga as a Route Server170163 Node: Description of the Route Server model171124 Ref: fig:normal-processing172701 Ref: fig:full-mesh173394 Ref: fig:route-server173572 Ref: filter-delegation174049 Ref: Route Server tasks175218 Ref: Route-server path filter process175589 Ref: fig:rs-processing177903 Node: Commands for configuring a Route Server180312 Node: Example of Route Server Configuration183339 Node: Configuration of the BGP routers without Route Server184260 Node: Configuration of the BGP routers with Route Server186848 Node: Configuration of the Route Server itself188049 Node: Further considerations about Import and Export route-maps192648 Node: VTY shell195517 Node: VTY shell username196210 Node: VTY shell integrated configuration196842 Node: Filtering198290 Node: IP Access List198643 Node: IP Prefix List199019 Node: ip prefix-list description202038 Node: ip prefix-list sequential number control202565 Node: Showing ip prefix-list203107 Node: Clear counter of ip prefix-list204215 Node: Route Map204654 Node: Route Map Command208099 Node: Route Map Match Command208408 Node: Route Map Set Command209032 Node: Route Map Call Command209940 Node: Route Map Exit Action Command210270 Node: Route Map Examples210752 Node: IPv6 Support211249 Node: Router Advertisement211828 Node: Kernel Interface218131 Node: SNMP Support220088 Node: Getting and installing an SNMP agent220747 Node: AgentX configuration221556 Node: SMUX configuration223230 Node: MIB and command reference225237 Node: Handling SNMP Traps226708 Node: Zebra Protocol232771 Node: Packet Binary Dump Format236800 Node: Command Index247700 Node: VTY Key Index311280 Node: Index314196  End Tag Table quagga-0.99.22.4/doc/quagga.info-10000644000175000017500000074362412211704577013300 00000000000000This is quagga.info, produced by makeinfo version 4.13 from quagga.texi. {No value for `COPYRIGHT_STR'} 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 * {No value for `PACKAGE_NAME'}: (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 0.99.22.4, last updated 4 August 2013 of `The Quagga Manual', for {No value for `PACKAGE_NAME'} Version 0.99.22.4. {No value for `COPYRIGHT_STR'} 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 {No value for `PACKAGE_STRING'}. Quagga is a fork of GNU Zebra. {No value for `COPYRIGHT_STR'} 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:: * Babel:: * 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: `http://www.quagga.net/' 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: `http://www.zebra.org/'.  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: `http://lists.quagga.net/mailman/listinfo/quagga-users'. The Quagga site has further information on the available mailing lists, see: `http://www.quagga.net/lists.php'  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: `http://bugzilla.quagga.net' 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 `http://bugzilla.quagga.net'.  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. `--enable-guile' Turn on compilation of the zebra-guile interpreter. You will need the guile library to make this. zebra-guile implementation is not yet finished. So this option is only useful for zebra-guile developers. `--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 (internet-draft) this requires support for Opaque LSAs. `--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. `--disable-tests' Do not build tests. Test programs are built by default, but not ran or installed. They can be excluded from build with this option, which will minimally decrease compile time and overhead. They can always be built and executed at a later time by running `make check' in the `tests/' subdirectory, even if they're excluded from build. 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 `ftp://ftp.inner.net/pub/ipv6/'. `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 `http://www.tazenda.demon.co.uk/phil/net-tools/'. ---------- 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 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 `{No value for `INSTALL_PREFIX_ETC'}/*.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: * Terminal Mode Commands:: Common commands used in a VTY * Config Commands:: Commands used in config files * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons  File: quagga.info, Node: Config Commands, Next: Common Invocation Options, Prev: 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: `{No value for `INSTALL_PREFIX_ETC'}/*.conf' Each of the daemons has its own config file. For example, zebra's default config file name is: `{No value for `INSTALL_PREFIX_ETC'}/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: 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: 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 {No value for `PACKAGE_NAME'} 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: Config Commands, Up: Basic commands 3.3 Common Invocation Options ============================= These options apply to all {No value for `PACKAGE_NAME'} 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 {No value for `PACKAGE_NAME'} 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 {No value for `PACKAGE_NAME'} (version 0.99.22.4) {No value for `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# '?' 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.  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.  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 * 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 ====================== -- 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: Static Route Commands, Next: zebra Route Filtering, 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.255.255.0 10.0.0.2 ip route 10.0.0.0 255.255.255.0 ppp0 ip route 10.0.0.0 255.255.255.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: zebra Route Filtering, Next: zebra FIB push interface, Prev: Static Route Commands, Up: Zebra 4.4 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.5 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 format of the messages exchanged with the FPM is defined by the file `fpm/fpm.h' in the quagga tree. 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.6 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 {No value for `INSTALL_PREFIX_ETC'}. 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 protocols The command displays current RIP status. It includes RIP timer, filtering, version, RIP enabled interface and RIP peer inforation. ripd> show ip protocols Routing Protocol is "rip" Sending updates every 30 seconds with +/-50%, next due in 35 seconds Timeout after 180 seconds, garbage collect after 120 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 Redistributing: kernel connected Default version control: send version 2, receive version 2 Interface Send Recv Routing for Networks: eth0 eth1 1.1.1.1 203.181.89.241 Routing Information Sources: Gateway BadPackets BadRoutes Distance Last Update  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: * Configuring ospfd:: * OSPF router:: * OSPF area:: * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: * Debugging OSPF:: * OSPF Configuration Examples::  File: quagga.info, Node: Configuring ospfd, Next: OSPF router, Up: OSPFv2 7.1 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.2 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.  File: quagga.info, Node: OSPF area, Next: OSPF interface, Prev: OSPF router, Up: OSPFv2 7.3 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.4 OSPF interface ================== -- 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.5 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: Debugging OSPF, Prev: Redistribute routes to OSPF, Up: OSPFv2 7.6 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|external|network|router|summary) -- Command: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID -- Command: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER -- Command: show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER -- Command: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate -- Command: show ip ospf database (asbr-summary|external|network|router|summary) 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: Debugging OSPF, Next: OSPF Configuration Examples, Prev: Showing OSPF information, Up: OSPFv2 7.7 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] -- Command: debug ospf ism -- Command: debug ospf ism (status|events|timers) -- Command: no debug ospf ism -- Command: no debug ospf ism (status|events|timers) -- Command: debug ospf nsm -- Command: debug ospf nsm (status|events|timers) -- Command: no debug ospf nsm -- Command: no debug ospf nsm (status|events|timers) -- Command: debug ospf lsa -- Command: debug ospf lsa (generate|flooding|refresh) -- Command: no debug ospf lsa -- Command: no debug ospf lsa (generate|flooding|refresh) -- Command: debug ospf zebra -- Command: debug ospf zebra (interface|redistribute) -- Command: no debug ospf zebra -- Command: no debug ospf zebra (interface|redistribute) -- Command: show debugging ospf  File: quagga.info, Node: OSPF Configuration Examples, Prev: Debugging OSPF, Up: OSPFv2 7.8 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 !  File: quagga.info, Node: OSPFv3, Next: Babel, 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.  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 is 1. -- 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.  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: Babel, Next: BGP, Prev: OSPFv3, Up: Top 9 Babel ******* Babel is an interior gateway protocol that is suitable both for wired networks and for wireless mesh networks. Babel has been described as "RIP on speed" -- it is based on the same principles as RIP, but includes a number of refinements that make it react much faster to topology changes without ever counting to infinity, and allow it to perform reliable link quality estimation on wireless links. Babel is a double-stack routing protocol, meaning that a single Babel instance is able to perform routing for both IPv4 and IPv6. Quagga implements Babel as described in RFC6126. * Menu: * Configuring babeld:: * Babel configuration:: * Babel redistribution:: * Show Babel information:: * Babel debugging commands::  File: quagga.info, Node: Configuring babeld, Next: Babel configuration, Prev: Babel, Up: Babel 9.1 Configuring babeld ====================== The `babeld' daemon can be invoked with any of the common options (*note Common Invocation Options::). The `zebra' daemon must be running before `babeld' is invoked. Also, if `zebra' is restarted then `babeld' must be too. Configuration of `babeld' is done in its configuration file `babeld.conf'.  File: quagga.info, Node: Babel configuration, Next: Babel redistribution, Prev: Configuring babeld, Up: Babel 9.2 Babel configuration ======================= -- Command: router babel -- Command: no router babel Enable or disable Babel routing. -- Babel Command: network IFNAME -- Babel Command: no network IFNAME Enable or disable Babel on the given interface. -- Interface Command: babel wired -- Interface Command: babel wireless Specifies whether this interface is wireless, which disables a number of optimisations that are only correct on wired interfaces. Specifying `wireless' (the default) is always correct, but may cause slower convergence and extra routing traffic. -- Interface Command: babel split-horizon -- Interface Command: no babel split-horizon Specifies whether to perform split-horizon on the interface. Specifying `no babel split-horizon' (the default) is always correct, while `babel split-horizon' is an optimisation that should only be used on symmetric and transitive (wired) networks. -- Interface Command: babel hello-interval <20-655340> Specifies the time in milliseconds between two scheduled hellos. On wired links, Babel notices a link failure within two hello intervals; on wireless links, the link quality value is reestimated at every hello interval. The default is 4000ms. -- Interface Command: babel update-interval <20-655340> Specifies the time in milliseconds between two scheduled updates. Since Babel makes extensive use of triggered updates, this can be set to fairly high values on links with little packet loss. The default is 20000ms. -- Babel Command: babel resend-delay <20-655340> Specifies the time in milliseconds after which an "important" request or update will be resent. The default is 2000ms. You probably don't want to tweak this value.  File: quagga.info, Node: Babel redistribution, Next: Show Babel information, Prev: Babel configuration, Up: Babel 9.3 Babel redistribution ======================== -- Babel command: redistribute KIND -- Babel command: no redistribute KIND Specify which kind of routes should be redistributed into Babel.  File: quagga.info, Node: Show Babel information, Next: Babel debugging commands, Prev: Babel redistribution, Up: Babel 9.4 Show Babel information ========================== -- Command: show babel database -- Command: show babel interface -- Command: show babel neighbour -- Command: show babel parameters These commands dump various parts of `babeld''s internal state. They are mostly useful for troubleshooting.  File: quagga.info, Node: Babel debugging commands, Prev: Show Babel information, Up: Babel 9.5 Babel debugging commands ============================ -- Babel Command: debug babel KIND -- Babel Command: no debug babel KIND Enable or disable debugging messages of a given kind. KIND can be one of `common', `kernel', `filter', `timeout', `interface', `route' or `all'. Note that if you have compiled with the NO_DEBUG flag, then these commands aren't available.  File: quagga.info, Node: BGP, Next: Configuring Quagga as a Route Server, Prev: Babel, Up: Top 10 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 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 10.1 Starting BGP ================= Default configuration file of `bgpd' is `bgpd.conf'. `bgpd' searches the current directory first then {No value for `INSTALL_PREFIX_ETC'}/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.  File: quagga.info, Node: BGP router, Next: BGP network, Prev: Starting BGP, Up: BGP 10.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 10.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. -- 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 10.2.2 BGP decision process --------------------------- 1. Weight check 2. Local preference check. 3. Local route check. 4. AS path length check. 5. Origin check. 6. MED check. -- 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.  File: quagga.info, Node: BGP route flap dampening, Prev: BGP decision process, Up: BGP router 10.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 network, Next: BGP Peer, Prev: BGP router, Up: BGP 10.3 BGP network ================ * Menu: * BGP route:: * Route Aggregation:: * Redistribute to BGP::  File: quagga.info, Node: BGP route, Next: Route Aggregation, Up: BGP network 10.3.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 10.3.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 inlucde 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 10.3.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 10.4 BGP Peer ============= * Menu: * Defining Peer:: * BGP Peer commands:: * Peer filtering::  File: quagga.info, Node: Defining Peer, Next: BGP Peer commands, Up: BGP Peer 10.4.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 10.4.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 -- BGP: no neighbor PEER next-hop-self This command specifies an announced route's nexthop as being equivalent to the address of the bgp router. -- 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.  File: quagga.info, Node: Peer filtering, Prev: BGP Peer commands, Up: BGP Peer 10.4.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'.  File: quagga.info, Node: BGP Peer Group, Next: BGP Address Family, Prev: BGP Peer, Up: BGP 10.5 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 10.6 BGP Address Family =======================  File: quagga.info, Node: Autonomous System, Next: BGP Communities Attribute, Prev: BGP Address Family, Up: BGP 10.7 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 10.7.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 10.7.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 10.7.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 10.7.4 Using AS Path in Route Map --------------------------------- -- Route Map: match as-path WORD -- Route Map: set as-path prepend AS-PATH  File: quagga.info, Node: Private AS Numbers, Prev: Using AS Path in Route Map, Up: Autonomous System 10.7.5 Private AS Numbers -------------------------  File: quagga.info, Node: BGP Communities Attribute, Next: BGP Extended Communities Attribute, Prev: Autonomous System, Up: BGP 10.8 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 10.8.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 10.8.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 10.8.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 10.8.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 10.8.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 or 0:90. Network operator can put special internal communities value at BGP border router, then limit the BGP routes announcement into the internal network. 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 10.9 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 10.9.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 10.9.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 10.10 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 10.10.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 10.10.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 10.11 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 10.12 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 10.13 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 10.13.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 10.13.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 10.13.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 10.13.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 10.14 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 10.15 Dump BGP packets and table ================================ -- Command: dump bgp all PATH -- Command: dump bgp all PATH INTERVAL Dump all BGP packet and events to PATH file. -- Command: dump bgp updates PATH -- Command: dump bgp updates PATH INTERVAL Dump BGP updates to PATH file. -- Command: dump bgp routes PATH -- Command: dump bgp routes PATH Dump whole BGP routing table to PATH. This is heavy process.  File: quagga.info, Node: BGP Configuration Examples, Prev: Dump BGP packets and table, Up: BGP 10.16 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 11 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 (*note fig:full-mesh::), we can convert it into a centralized scenario where each of the four establishes a single BGP peering against the Route Server (*note fig: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 11.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 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 11.1: Announcement processing inside a "normal" BGP speaker [image src="fig_topologies_full.png" alt="Full Mesh BGP Topology" text="(RF1)--(RF2) | \\ / | | \\/ | | /\\ | | / \\ | (RF3)--(RF4) "] Figure 11.2: Full Mesh [image src="fig_topologies_rs.png" alt="Route Server BGP Topology" text="(RF1) (RF2) \\ / [RS] / \\ (RF3) (RF4) "] Figure 11.3: Route Server and clients 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 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 11.4: 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 11.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 11.4: 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 11.4: 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 11.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 11.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 11.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 11.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 11.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 12 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 {No value for `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::  File: quagga.info, Node: VTY shell username, Next: VTY shell integrated configuration, Up: VTY shell 12.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 12.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 13 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 13.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 13.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 13.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 13.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 13.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 13.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 14 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 14.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 14.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 aspath AS_PATH Matches the specified AS_PATH. -- Route-map Command: match metric METRIC Matches the specified METRIC. -- 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 14.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 14.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 14.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 14.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 15 IPv6 Support *************** Quagga fully supports IPv6 routing. As described so far, Quagga supports RIPng, OSPFv3, Babel 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 15.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 16 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 17 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 17.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 `http://www.net-snmp.org/' 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 17.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 17.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'.  File: quagga.info, Node: MIB and command reference, Next: Handling SNMP Traps, Prev: SMUX configuration, Up: SNMP Support 17.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 17.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 `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 ;). #!/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. Two versions of the header are in use. Version 0 is implicitely versioned. Version 1 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 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. We do not anticipate there will be further versions of the header for the foreseeable future, as the command field in version 1 is wide enough to allow for future extensions to done compatibly through seperate commands. 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. Version 1 will be used as of Quagga 1.0. 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) ---------------------------------------------- 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 Header Field Definitions --------------------------------------------- `Length' Total packet length including this header. The minimum length is 3 bytes for version 0 messages and 6 bytes for version 1 messages. `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. `Command' The Zebra Protocol command. A.2.4 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, `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 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3 quagga-0.99.22.4/doc/quagga.info-20000644000175000017500000021457312211704577013275 00000000000000This is quagga.info, produced by makeinfo version 4.13 from quagga.texi. {No value for `COPYRIGHT_STR'} 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 * {No value for `PACKAGE_NAME'}: (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 0.99.22.4, last updated 4 August 2013 of `The Quagga Manual', for {No value for `PACKAGE_NAME'} Version 0.99.22.4. {No value for `COPYRIGHT_STR'} 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: 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 142) * access-list NAME deny IPV4-NETWORK: IP Access List. (line 8) * access-list NAME permit IPV4-NETWORK: IP Access List. (line 7) * agentx: MIB and command reference. (line 35) * aggregate-address A.B.C.D/M: Route Aggregation. (line 7) * aggregate-address A.B.C.D/M as-set: Route Aggregation. (line 10) * aggregate-address A.B.C.D/M summary-only: Route Aggregation. (line 14) * area <0-4294967295> authentication: OSPF area. (line 127) * area <0-4294967295> authentication message-digest: OSPF area. (line 134) * area <0-4294967295> export-list NAME: OSPF area. (line 85) * area <0-4294967295> filter-list prefix NAME in: OSPF area. (line 117) * area <0-4294967295> filter-list prefix NAME out: OSPF area. (line 118) * area <0-4294967295> import-list NAME: OSPF area. (line 109) * area <0-4294967295> range A.B.C.D/M: OSPF area. (line 8) * area <0-4294967295> shortcut: OSPF area. (line 55) * area <0-4294967295> stub: OSPF area. (line 62) * area <0-4294967295> stub no-summary: OSPF area. (line 74) * area <0-4294967295> virtual-link A.B.C.D: OSPF area. (line 50) * area A.B.C.D authentication: OSPF area. (line 126) * area A.B.C.D authentication message-digest: OSPF area. (line 133) * area A.B.C.D default-cost <0-16777215>: OSPF area. (line 80) * area A.B.C.D export-list NAME: OSPF area. (line 84) * area A.B.C.D filter-list prefix NAME in: OSPF area. (line 115) * area A.B.C.D filter-list prefix NAME out: OSPF area. (line 116) * area A.B.C.D import-list NAME: OSPF area. (line 108) * area A.B.C.D range A.B.C.D/M: OSPF area. (line 7) * area A.B.C.D range IPV4_PREFIX not-advertise: OSPF area. (line 28) * area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX: OSPF area. (line 34) * area A.B.C.D shortcut: OSPF area. (line 54) * area A.B.C.D stub: OSPF area. (line 61) * area A.B.C.D stub no-summary: OSPF area. (line 73) * area A.B.C.D virtual-link A.B.C.D: OSPF area. (line 49) * auto-cost reference-bandwidth <1-4294967>: OSPF router. (line 163) * babel hello-interval <20-655340>: Babel configuration. (line 29) * babel resend-delay <20-655340>: Babel configuration. (line 41) * babel split-horizon: Babel configuration. (line 22) * babel update-interval <20-655340>: Babel configuration. (line 35) * babel wired: Babel configuration. (line 15) * babel wireless: Babel configuration. (line 16) * bandwidth <1-10000000>: Interface Commands. (line 31) * banner motd default: Basic Config Commands. (line 124) * bgp bestpath as-path confed: BGP decision process. (line 19) * bgp cluster-id A.B.C.D: Route Reflector. (line 7) * bgp config-type cisco: Multiple instance. (line 20) * bgp config-type zebra: Multiple instance. (line 53) * bgp dampening <1-45> <1-20000> <1-20000> <1-255>: BGP route flap dampening. (line 7) * bgp multiple-instance: Multiple instance. (line 10) * bgp router-id A.B.C.D: BGP router. (line 22) * call NAME: Route Map Call Command. (line 7) * call WORD: Commands for configuring a Route Server. (line 52) * clear ip bgp PEER: More Show IP BGP. (line 25) * clear ip bgp PEER soft in: More Show IP BGP. (line 28) * clear ip prefix-list: Clear counter of ip prefix-list. (line 7) * clear ip prefix-list NAME: Clear counter of ip prefix-list. (line 11) * clear ip prefix-list NAME A.B.C.D/M: Clear counter of ip prefix-list. (line 13) * clear zebra fpm stats: zebra Terminal Mode Commands. (line 41) * configure terminal: Terminal Mode Commands. (line 13) * continue: Route Map Exit Action Command. (line 8) * continue N: Route Map Exit Action Command. (line 12) * debug babel KIND: Babel debugging commands. (line 7) * debug event: More Show IP BGP. (line 39) * debug keepalive: More Show IP BGP. (line 43) * debug ospf ism: Debugging OSPF. (line 12) * debug ospf ism (status|events|timers): Debugging OSPF. (line 13) * debug ospf lsa: Debugging OSPF. (line 22) * debug ospf lsa (generate|flooding|refresh): Debugging OSPF. (line 23) * debug ospf nsm: Debugging OSPF. (line 17) * debug ospf nsm (status|events|timers): Debugging OSPF. (line 18) * debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]: Debugging OSPF. (line 8) * debug ospf zebra: Debugging OSPF. (line 27) * debug ospf zebra (interface|redistribute): Debugging OSPF. (line 28) * debug rip events: RIP Debug Commands. (line 9) * debug rip packet: RIP Debug Commands. (line 15) * debug rip zebra: RIP Debug Commands. (line 22) * debug ripng events: ripngd Terminal Mode Commands. (line 11) * debug ripng packet: ripngd Terminal Mode Commands. (line 13) * debug ripng zebra: ripngd Terminal Mode Commands. (line 15) * debug update: More Show IP BGP. (line 41) * default-information originate <1>: Redistribute routes to OSPF. (line 37) * default-information originate: How to Announce RIP route. (line 51) * default-information originate always: Redistribute routes to OSPF. (line 43) * default-information originate always metric <0-16777214>: Redistribute routes to OSPF. (line 45) * default-information originate always metric <0-16777214> metric-type (1|2): Redistribute routes to OSPF. (line 47) * default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 49) * default-information originate metric <0-16777214>: Redistribute routes to OSPF. (line 38) * default-information originate metric <0-16777214> metric-type (1|2): Redistribute routes to OSPF. (line 40) * default-information originate metric <0-16777214> metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 42) * default-metric <0-16777214>: Redistribute routes to OSPF. (line 65) * default-metric <1-16>: RIP Metric Manipulation. (line 11) * description DESCRIPTION ...: Interface Commands. (line 24) * distance <1-255> <1>: Redistribute routes to OSPF. (line 68) * distance <1-255>: RIP distance. (line 9) * distance <1-255> A.B.C.D/M <1>: BGP distance. (line 12) * distance <1-255> A.B.C.D/M: RIP distance. (line 13) * distance <1-255> A.B.C.D/M ACCESS-LIST: RIP distance. (line 18) * distance <1-255> A.B.C.D/M WORD: BGP distance. (line 13) * distance bgp <1-255> <1-255> <1-255>: BGP distance. (line 7) * distance ospf (intra-area|inter-area|external) <1-255>: Redistribute routes to OSPF. (line 72) * distribute-list ACCESS_LIST (in|out) IFNAME: ripngd Filtering Commands. (line 7) * distribute-list ACCESS_LIST DIRECT IFNAME: Filtering RIP Routes. (line 9) * distribute-list NAME out (kernel|connected|static|rip|ospf: Redistribute routes to OSPF. (line 58) * distribute-list prefix PREFIX_LIST (in|out) IFNAME: Filtering RIP Routes. (line 32) * dump bgp all PATH: Dump BGP packets and table. (line 7) * dump bgp all PATH INTERVAL: Dump BGP packets and table. (line 8) * dump bgp routes PATH: Dump BGP packets and table. (line 15) * dump bgp updates PATH: Dump BGP packets and table. (line 11) * dump bgp updates PATH INTERVAL: Dump BGP packets and table. (line 12) * enable password PASSWORD: Basic Config Commands. (line 14) * exec-timeout MINUTE: Basic Config Commands. (line 130) * exec-timeout MINUTE SECOND: Basic Config Commands. (line 131) * flush_timer TIME: ripngd Configuration. (line 12) * hostname HOSTNAME: Basic Config Commands. (line 7) * interface IFNAME: Interface Commands. (line 7) * interface IFNAME area AREA: OSPF6 router. (line 12) * ip address ADDRESS/PREFIX: Interface Commands. (line 13) * ip address ADDRESS/PREFIX secondary: Interface Commands. (line 19) * ip as-path access-list WORD {permit|deny} LINE: AS Path Access List. (line 9) * ip community-list <1-99> {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 14) * ip community-list <100-199> {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 20) * ip community-list expanded NAME {permit|deny} LINE: BGP Community Lists. (line 30) * ip community-list NAME {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 25) * ip community-list standard NAME {permit|deny} COMMUNITY: BGP Community Lists. (line 20) * ip extcommunity-list expanded NAME {permit|deny} LINE: BGP Extended Community Lists. (line 21) * ip extcommunity-list standard NAME {permit|deny} EXTCOMMUNITY: BGP Extended Community Lists. (line 10) * ip ospf authentication message-digest: OSPF interface. (line 17) * ip ospf authentication-key AUTH_KEY: OSPF interface. (line 7) * ip ospf cost <1-65535>: OSPF interface. (line 45) * ip ospf dead-interval <1-65535>: OSPF interface. (line 50) * ip ospf dead-interval minimal hello-multiplier <2-20>: OSPF interface. (line 52) * ip ospf hello-interval <1-65535>: OSPF interface. (line 69) * ip ospf message-digest-key KEYID md5 KEY: OSPF interface. (line 33) * ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point): OSPF interface. (line 80) * ip ospf priority <0-255>: OSPF interface. (line 84) * ip ospf retransmit-interval <1-65535>: OSPF interface. (line 91) * ip ospf transmit-delay: OSPF interface. (line 97) * ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN]: IP Prefix List. (line 16) * ip prefix-list NAME description DESC: ip prefix-list description. (line 7) * ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN]: IP Prefix List. (line 18) * ip prefix-list sequence-number: ip prefix-list sequential number control. (line 7) * ip protocol PROTOCOL route-map ROUTEMAP: zebra Route Filtering. (line 12) * ip rip authentication key-chain KEY-CHAIN: RIP Authentication. (line 43) * ip rip authentication mode md5: RIP Authentication. (line 29) * ip rip authentication mode text: RIP Authentication. (line 33) * ip rip authentication string STRING: RIP Authentication. (line 37) * ip rip receive version VERSION: RIP Version Control. (line 44) * ip rip send version VERSION: RIP Version Control. (line 33) * ip route NETWORK GATEWAY: Static Route Commands. (line 10) * ip route NETWORK GATEWAY DISTANCE: Static Route Commands. (line 36) * ip route NETWORK NETMASK GATEWAY: Static Route Commands. (line 25) * ip split-horizon: RIP Configuration. (line 70) * ipv6 address ADDRESS/PREFIX: Interface Commands. (line 14) * ipv6 nd adv-interval-option: Router Advertisement. (line 127) * ipv6 nd home-agent-config-flag: Router Advertisement. (line 101) * ipv6 nd home-agent-lifetime <0-65520>: Router Advertisement. (line 118) * 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 142) * 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 14) * 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 135) * ipv6 nd suppress-ra: Router Advertisement. (line 10) * ipv6 ospf6 cost COST: OSPF6 interface. (line 7) * ipv6 ospf6 dead-interval DEADINTERVAL: OSPF6 interface. (line 13) * ipv6 ospf6 hello-interval HELLOINTERVAL: OSPF6 interface. (line 10) * ipv6 ospf6 priority PRIORITY: OSPF6 interface. (line 20) * ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL: OSPF6 interface. (line 17) * ipv6 ospf6 transmit-delay TRANSMITDELAY: OSPF6 interface. (line 23) * ipv6 route NETWORK GATEWAY: Static Route Commands. (line 77) * ipv6 route NETWORK GATEWAY DISTANCE: Static Route Commands. (line 78) * line vty: Basic Config Commands. (line 121) * link-detect: Interface Commands. (line 37) * list: Terminal Mode Commands. (line 24) * log facility FACILITY: Basic Config Commands. (line 81) * log file FILENAME: Basic Config Commands. (line 41) * log file FILENAME LEVEL: Basic Config Commands. (line 42) * log monitor: Basic Config Commands. (line 68) * log monitor LEVEL: Basic Config Commands. (line 69) * log record-priority: Basic Config Commands. (line 87) * log stdout: Basic Config Commands. (line 28) * log stdout LEVEL: Basic Config Commands. (line 29) * log syslog: Basic Config Commands. (line 59) * log syslog LEVEL: Basic Config Commands. (line 60) * log timestamp precision <0-6>: Basic Config Commands. (line 97) * log trap LEVEL: Basic Config Commands. (line 17) * log-adjacency-changes [detail]: OSPF router. (line 73) * logmsg LEVEL MESSAGE: Terminal Mode Commands. (line 35) * match as-path WORD: Using AS Path in Route Map. (line 7) * match aspath AS_PATH: Route Map Match Command. (line 13) * match community COMMUNITY_LIST: Route Map Match Command. (line 19) * match community WORD: BGP Community in Route Map. (line 13) * match community WORD exact-match: BGP Community in Route Map. (line 14) * match extcommunity WORD: BGP Extended Communities in Route Map. (line 7) * match interface WORD: RIP route-map. (line 26) * match ip address ACCESS_LIST: Route Map Match Command. (line 7) * match ip address prefix-list WORD: RIP route-map. (line 39) * match ip address WORD: RIP route-map. (line 38) * match ip next-hop IPV4_ADDR: Route Map Match Command. (line 10) * match ip next-hop prefix-list WORD: RIP route-map. (line 43) * match ip next-hop WORD: RIP route-map. (line 42) * match metric <0-4294967295>: RIP route-map. (line 48) * match metric METRIC: Route Map Match Command. (line 16) * match peer {A.B.C.D|X:X::X:X}: Commands for configuring a Route Server. (line 34) * max-metric router-lsa [on-startup|on-shutdown] <5-86400>: OSPF router. (line 130) * max-metric router-lsa administrative: OSPF router. (line 131) * multicast: Interface Commands. (line 27) * neigbor {A.B.C.D|X.X::X.X|peer-group} route-map WORD {import|export}: Commands for configuring a Route Server. (line 29) * neighbor A.B.C.D: RIP Configuration. (line 34) * neighbor A.B.C.D route-server-client: Commands for configuring a Route Server. (line 11) * neighbor PEER default-originate: BGP Peer commands. (line 59) * neighbor PEER description ...: BGP Peer commands. (line 20) * neighbor PEER distribute-list NAME [in|out]: Peer filtering. (line 7) * neighbor PEER dont-capability-negotiate: Capability Negotiation. (line 51) * neighbor PEER ebgp-multihop: BGP Peer commands. (line 17) * neighbor PEER filter-list NAME [in|out]: Peer filtering. (line 13) * neighbor PEER interface IFNAME: BGP Peer commands. (line 33) * neighbor PEER local-as AS-NUMBER: BGP Peer commands. (line 79) * neighbor PEER local-as AS-NUMBER no-prepend: BGP Peer commands. (line 80) * neighbor PEER local-as AS-NUMBER no-prepend replace-as: BGP Peer commands. (line 81) * neighbor PEER maximum-prefix NUMBER: BGP Peer commands. (line 76) * neighbor PEER next-hop-self: BGP Peer commands. (line 43) * neighbor PEER override-capability: Capability Negotiation. (line 67) * neighbor PEER peer-group WORD: BGP Peer Group. (line 10) * neighbor PEER port PORT: BGP Peer commands. (line 65) * neighbor PEER prefix-list NAME [in|out]: Peer filtering. (line 11) * neighbor PEER remote-as ASN: Defining Peer. (line 7) * neighbor PEER route-map NAME [in|out]: Peer filtering. (line 15) * neighbor PEER route-reflector-client: Route Reflector. (line 9) * neighbor PEER send-community: BGP Peer commands. (line 68) * neighbor PEER shutdown: BGP Peer commands. (line 10) * neighbor PEER strict-capability-match: Capability Negotiation. (line 40) * neighbor PEER update-source : BGP Peer commands. (line 48) * neighbor PEER version VERSION: BGP Peer commands. (line 24) * neighbor PEER weight WEIGHT: BGP Peer commands. (line 71) * neighbor PEER-GROUP route-server-client: Commands for configuring a Route Server. (line 10) * neighbor WORD peer-group: BGP Peer Group. (line 7) * neighbor X:X::X:X route-server-client: Commands for configuring a Route Server. (line 12) * network A.B.C.D/M: BGP route. (line 7) * network A.B.C.D/M area <0-4294967295>: OSPF router. (line 175) * network A.B.C.D/M area A.B.C.D: OSPF router. (line 174) * network IFNAME <1>: Babel configuration. (line 11) * network IFNAME <2>: ripngd Configuration. (line 18) * network IFNAME: RIP Configuration. (line 27) * network NETWORK <1>: ripngd Configuration. (line 15) * network NETWORK: RIP Configuration. (line 15) * no agentx: MIB and command reference. (line 36) * no aggregate-address A.B.C.D/M: Route Aggregation. (line 18) * no area <0-4294967295> authentication: OSPF area. (line 129) * no area <0-4294967295> export-list NAME: OSPF area. (line 87) * no area <0-4294967295> filter-list prefix NAME in: OSPF area. (line 121) * no area <0-4294967295> filter-list prefix NAME out: OSPF area. (line 122) * no area <0-4294967295> import-list NAME: OSPF area. (line 111) * no area <0-4294967295> range A.B.C.D/M: OSPF area. (line 10) * no area <0-4294967295> shortcut: OSPF area. (line 57) * no area <0-4294967295> stub: OSPF area. (line 64) * no area <0-4294967295> stub no-summary: OSPF area. (line 76) * no area <0-4294967295> virtual-link A.B.C.D: OSPF area. (line 52) * no area A.B.C.D authentication: OSPF area. (line 128) * no area A.B.C.D default-cost <0-16777215>: OSPF area. (line 81) * no area A.B.C.D export-list NAME: OSPF area. (line 86) * no area A.B.C.D filter-list prefix NAME in: OSPF area. (line 119) * no area A.B.C.D filter-list prefix NAME out: OSPF area. (line 120) * no area A.B.C.D import-list NAME: OSPF area. (line 110) * no area A.B.C.D range A.B.C.D/M: OSPF area. (line 9) * no area A.B.C.D range IPV4_PREFIX not-advertise: OSPF area. (line 29) * no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX: OSPF area. (line 36) * no area A.B.C.D shortcut: OSPF area. (line 56) * no area A.B.C.D stub: OSPF area. (line 63) * no area A.B.C.D stub no-summary: OSPF area. (line 75) * no area A.B.C.D virtual-link A.B.C.D: OSPF area. (line 51) * no auto-cost reference-bandwidth: OSPF router. (line 164) * no babel split-horizon: Babel configuration. (line 23) * no bandwidth <1-10000000>: Interface Commands. (line 32) * no banner motd: Basic Config Commands. (line 127) * no bgp multiple-instance: Multiple instance. (line 14) * no debug babel KIND: Babel debugging commands. (line 8) * no debug event: More Show IP BGP. (line 45) * no debug keepalive: More Show IP BGP. (line 49) * no debug ospf ism: Debugging OSPF. (line 14) * no debug ospf ism (status|events|timers): Debugging OSPF. (line 15) * no debug ospf lsa: Debugging OSPF. (line 24) * no debug ospf lsa (generate|flooding|refresh): Debugging OSPF. (line 25) * no debug ospf nsm: Debugging OSPF. (line 19) * no debug ospf nsm (status|events|timers): Debugging OSPF. (line 20) * no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]: Debugging OSPF. (line 10) * no debug ospf zebra: Debugging OSPF. (line 29) * no debug ospf zebra (interface|redistribute): Debugging OSPF. (line 30) * no debug update: More Show IP BGP. (line 47) * no default-information originate: Redistribute routes to OSPF. (line 50) * no default-metric: Redistribute routes to OSPF. (line 66) * no default-metric <1-16>: RIP Metric Manipulation. (line 12) * no distance <1-255> <1>: Redistribute routes to OSPF. (line 69) * no distance <1-255>: RIP distance. (line 10) * no distance <1-255> A.B.C.D/M: RIP distance. (line 14) * no distance <1-255> A.B.C.D/M ACCESS-LIST: RIP distance. (line 19) * no distance ospf: Redistribute routes to OSPF. (line 73) * no distribute-list NAME out (kernel|connected|static|rip|ospf: Redistribute routes to OSPF. (line 60) * no exec-timeout: Basic Config Commands. (line 138) * no ip address ADDRESS/PREFIX: Interface Commands. (line 15) * no ip address ADDRESS/PREFIX secondary: Interface Commands. (line 20) * no ip as-path access-list WORD: AS Path Access List. (line 12) * no ip as-path access-list WORD {permit|deny} LINE: AS Path Access List. (line 13) * no ip community-list expanded NAME: BGP Community Lists. (line 37) * no ip community-list NAME: BGP Community Lists. (line 35) * no ip community-list standard NAME: BGP Community Lists. (line 36) * no ip extcommunity-list expanded NAME: BGP Extended Community Lists. (line 29) * no ip extcommunity-list NAME: BGP Extended Community Lists. (line 27) * no ip extcommunity-list standard NAME: BGP Extended Community Lists. (line 28) * no ip ospf authentication-key: OSPF interface. (line 8) * no ip ospf cost: OSPF interface. (line 46) * no ip ospf dead-interval: OSPF interface. (line 53) * no ip ospf hello-interval: OSPF interface. (line 70) * no ip ospf message-digest-key: OSPF interface. (line 34) * no ip ospf network: OSPF interface. (line 81) * no ip ospf priority: OSPF interface. (line 85) * no ip ospf retransmit interval: OSPF interface. (line 92) * no ip ospf transmit-delay: OSPF interface. (line 98) * no ip prefix-list NAME: IP Prefix List. (line 67) * no ip prefix-list NAME description [DESC]: ip prefix-list description. (line 11) * no ip prefix-list sequence-number: ip prefix-list sequential number control. (line 11) * no ip rip authentication key-chain KEY-CHAIN: RIP Authentication. (line 44) * no ip rip authentication mode md5: RIP Authentication. (line 30) * no ip rip authentication mode text: RIP Authentication. (line 34) * no ip rip authentication string STRING: RIP Authentication. (line 38) * no ip split-horizon: RIP Configuration. (line 71) * no ipv6 address ADDRESS/PREFIX: Interface Commands. (line 16) * no ipv6 nd adv-interval-option: Router Advertisement. (line 128) * no ipv6 nd home-agent-config-flag: Router Advertisement. (line 102) * no ipv6 nd home-agent-lifetime [<0-65520>]: Router Advertisement. (line 119) * 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 143) * 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 136) * no ipv6 nd suppress-ra: Router Advertisement. (line 7) * no link-detect: Interface Commands. (line 38) * no log facility: Basic Config Commands. (line 82) * no log file: Basic Config Commands. (line 43) * no log monitor: Basic Config Commands. (line 70) * no log record-priority: Basic Config Commands. (line 88) * no log stdout: Basic Config Commands. (line 30) * no log syslog: Basic Config Commands. (line 61) * no log timestamp precision: Basic Config Commands. (line 98) * no log trap: Basic Config Commands. (line 18) * no log-adjacency-changes [detail]: OSPF router. (line 74) * no max-metric router-lsa [on-startup|on-shutdown|administrative]: OSPF router. (line 133) * no multicast: Interface Commands. (line 28) * no neighbor A.B.C.D: RIP Configuration. (line 35) * no neighbor PEER default-originate: BGP Peer commands. (line 60) * no neighbor PEER description ...: BGP Peer commands. (line 21) * no neighbor PEER dont-capability-negotiate: Capability Negotiation. (line 52) * no neighbor PEER ebgp-multihop: BGP Peer commands. (line 18) * no neighbor PEER interface IFNAME: BGP Peer commands. (line 34) * no neighbor PEER local-as: BGP Peer commands. (line 82) * no neighbor PEER maximum-prefix NUMBER: BGP Peer commands. (line 77) * no neighbor PEER next-hop-self: BGP Peer commands. (line 44) * no neighbor PEER override-capability: Capability Negotiation. (line 68) * no neighbor PEER route-reflector-client: Route Reflector. (line 10) * no neighbor PEER shutdown: BGP Peer commands. (line 11) * no neighbor PEER strict-capability-match: Capability Negotiation. (line 41) * no neighbor PEER update-source: BGP Peer commands. (line 49) * no neighbor PEER weight WEIGHT: BGP Peer commands. (line 72) * no network A.B.C.D/M: BGP route. (line 16) * no network A.B.C.D/M area <0-4294967295>: OSPF router. (line 177) * no network A.B.C.D/M area A.B.C.D: OSPF router. (line 176) * no network IFNAME <1>: Babel configuration. (line 12) * no network IFNAME: RIP Configuration. (line 28) * no network NETWORK: RIP Configuration. (line 16) * no ospf abr-type TYPE: OSPF router. (line 27) * no ospf rfc1583compatibility: OSPF router. (line 63) * no ospf router-id: OSPF router. (line 17) * no passive-interface IFNAME: RIP Configuration. (line 58) * no passive-interface INTERFACE: OSPF router. (line 80) * no redistribute (kernel|connected|static|rip|bgp): Redistribute routes to OSPF. (line 22) * no redistribute bgp: How to Announce RIP route. (line 44) * no redistribute connected: How to Announce RIP route. (line 26) * no redistribute kernel: How to Announce RIP route. (line 10) * no redistribute KIND: Babel redistribution. (line 8) * no redistribute ospf: How to Announce RIP route. (line 36) * no redistribute static: How to Announce RIP route. (line 18) * no route A.B.C.D/M: How to Announce RIP route. (line 54) * no router babel: Babel configuration. (line 8) * no router bgp ASN: BGP router. (line 19) * no router ospf: OSPF router. (line 11) * no router rip: RIP Configuration. (line 12) * no shutdown: Interface Commands. (line 10) * no smux peer OID: MIB and command reference. (line 28) * no smux peer OID PASSWORD: MIB and command reference. (line 31) * no timers basic: RIP Timers. (line 31) * no timers throttle spf: OSPF router. (line 92) * no version: RIP Version Control. (line 30) * offset-list ACCESS-LIST (in|out): RIP Metric Manipulation. (line 20) * offset-list ACCESS-LIST (in|out) IFNAME: RIP Metric Manipulation. (line 21) * on-match goto N: Route Map Exit Action Command. (line 11) * on-match next: Route Map Exit Action Command. (line 7) * ospf abr-type TYPE: OSPF router. (line 26) * ospf rfc1583compatibility: OSPF router. (line 62) * ospf router-id A.B.C.D: OSPF router. (line 16) * passive-interface (IFNAME|default): RIP Configuration. (line 57) * passive-interface INTERFACE: OSPF router. (line 79) * password PASSWORD: Basic Config Commands. (line 10) * redistribute (kernel|connected|static|rip|bgp): Redistribute routes to OSPF. (line 7) * redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>: Redistribute routes to OSPF. (line 15) * redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD: Redistribute routes to OSPF. (line 17) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2): Redistribute routes to OSPF. (line 11) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>: Redistribute routes to OSPF. (line 19) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD: Redistribute routes to OSPF. (line 21) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 13) * redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP: Redistribute routes to OSPF. (line 9) * redistribute bgp: How to Announce RIP route. (line 41) * redistribute bgp metric <0-16>: How to Announce RIP route. (line 42) * redistribute bgp route-map ROUTE-MAP: How to Announce RIP route. (line 43) * redistribute connected <1>: Redistribute to BGP. (line 13) * redistribute connected <2>: Redistribute routes to OSPF6. (line 8) * redistribute connected: How to Announce RIP route. (line 23) * redistribute connected metric <0-16>: How to Announce RIP route. (line 24) * redistribute connected route-map ROUTE-MAP: How to Announce RIP route. (line 25) * redistribute kernel <1>: Redistribute to BGP. (line 7) * redistribute kernel: How to Announce RIP route. (line 7) * redistribute kernel metric <0-16>: How to Announce RIP route. (line 8) * redistribute kernel route-map ROUTE-MAP: How to Announce RIP route. (line 9) * redistribute KIND: Babel redistribution. (line 7) * redistribute ospf <1>: Redistribute to BGP. (line 19) * redistribute ospf: How to Announce RIP route. (line 33) * redistribute ospf metric <0-16>: How to Announce RIP route. (line 34) * redistribute ospf route-map ROUTE-MAP: How to Announce RIP route. (line 35) * redistribute rip: Redistribute to BGP. (line 16) * redistribute ripng: Redistribute routes to OSPF6. (line 9) * redistribute static <1>: Redistribute to BGP. (line 10) * redistribute static <2>: Redistribute routes to OSPF6. (line 7) * redistribute static: How to Announce RIP route. (line 15) * redistribute static metric <0-16>: How to Announce RIP route. (line 16) * redistribute static route-map ROUTE-MAP: How to Announce RIP route. (line 17) * route A.B.C.D/M: How to Announce RIP route. (line 53) * route NETWORK: ripngd Configuration. (line 21) * route-map ROUTE-MAP-NAME (permit|deny) ORDER: Route Map Command. (line 7) * router babel: Babel configuration. (line 7) * router bgp AS-NUMBER: BGP instance and view. (line 11) * router bgp AS-NUMBER view NAME: BGP instance and view. (line 28) * router bgp ASN: BGP router. (line 13) * router ospf: OSPF router. (line 10) * router ospf6: OSPF6 router. (line 7) * router rip: RIP Configuration. (line 7) * router ripng: ripngd Configuration. (line 9) * router zebra: ripngd Configuration. (line 24) * router-id A.B.C.D: OSPF6 router. (line 9) * service advanced-vty: Basic Config Commands. (line 114) * service integrated-vtysh-config: VTY shell integrated configuration. (line 7) * service password-encryption: Basic Config Commands. (line 111) * service terminal-length <0-512>: Basic Config Commands. (line 117) * set as-path prepend AS-PATH: Using AS Path in Route Map. (line 9) * set as-path prepend AS_PATH: Route Map Set Command. (line 19) * set comm-list WORD delete: BGP Community in Route Map. (line 34) * set community COMMUNITY <1>: Route Map Set Command. (line 22) * set community COMMUNITY: BGP Community in Route Map. (line 23) * set community COMMUNITY additive: BGP Community in Route Map. (line 24) * set community none: BGP Community in Route Map. (line 22) * set extcommunity rt EXTCOMMUNITY: BGP Extended Communities in Route Map. (line 9) * set extcommunity soo EXTCOMMUNITY: BGP Extended Communities in Route Map. (line 12) * set ip next-hop A.B.C.D: RIP route-map. (line 53) * set ip next-hop IPV4_ADDRESS: Route Map Set Command. (line 7) * set ipv6 next-hop global IPV6_ADDRESS: Route Map Set Command. (line 25) * set ipv6 next-hop local IPV6_ADDRESS: Route Map Set Command. (line 28) * set local-preference LOCAL_PREF: Route Map Set Command. (line 10) * set metric <0-4294967295>: RIP route-map. (line 58) * set metric METRIC: Route Map Set Command. (line 16) * set src ADDRESS: zebra Route Filtering. (line 17) * set weight WEIGHT: Route Map Set Command. (line 13) * show babel database: Show Babel information. (line 7) * show babel interface: Show Babel information. (line 8) * show babel neighbour: Show Babel information. (line 9) * show babel parameters: Show Babel information. (line 10) * show debug: More Show IP BGP. (line 37) * show debugging ospf: Debugging OSPF. (line 32) * show debugging rip: RIP Debug Commands. (line 29) * show debugging ripng: ripngd Terminal Mode Commands. (line 9) * show interface: zebra Terminal Mode Commands. (line 21) * show ip bgp: Show IP BGP. (line 7) * show ip bgp A.B.C.D: Show IP BGP. (line 8) * show ip bgp community: Display BGP Routes by Community. (line 11) * show ip bgp community COMMUNITY <1>: More Show IP BGP. (line 11) * show ip bgp community COMMUNITY: Display BGP Routes by Community. (line 12) * show ip bgp community COMMUNITY exact-match <1>: More Show IP BGP. (line 12) * show ip bgp community COMMUNITY exact-match: Display BGP Routes by Community. (line 13) * show ip bgp community-list WORD <1>: More Show IP BGP. (line 16) * show ip bgp community-list WORD: Display BGP Routes by Community. (line 20) * show ip bgp community-list WORD exact-match <1>: More Show IP BGP. (line 17) * show ip bgp community-list WORD exact-match: Display BGP Routes by Community. (line 21) * show ip bgp dampened-paths: More Show IP BGP. (line 31) * show ip bgp flap-statistics: More Show IP BGP. (line 34) * show ip bgp neighbor [PEER]: More Show IP BGP. (line 23) * show ip bgp regexp LINE <1>: More Show IP BGP. (line 7) * show ip bgp regexp LINE: Display BGP Routes by AS Path. (line 10) * show ip bgp summary: More Show IP BGP. (line 21) * show ip bgp view NAME: Viewing the view. (line 9) * show ip bgp X:X::X:X: Show IP BGP. (line 9) * show ip community-list: BGP Community Lists. (line 42) * show ip community-list NAME: BGP Community Lists. (line 43) * show ip extcommunity-list: BGP Extended Community Lists. (line 35) * show ip extcommunity-list NAME: BGP Extended Community Lists. (line 36) * show ip ospf: Showing OSPF information. (line 7) * show ip ospf database: Showing OSPF information. (line 20) * show ip ospf database (asbr-summary|external|network|router|summary): Showing OSPF information. (line 23) * show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER: Showing OSPF information. (line 30) * show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID: Showing OSPF information. (line 25) * show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER: Showing OSPF information. (line 28) * show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate: Showing OSPF information. (line 33) * show ip ospf database (asbr-summary|external|network|router|summary) self-originate: Showing OSPF information. (line 35) * show ip ospf database max-age: Showing OSPF information. (line 37) * show ip ospf database self-originate: Showing OSPF information. (line 39) * show ip ospf interface [INTERFACE]: Showing OSPF information. (line 11) * show ip ospf neighbor: Showing OSPF information. (line 15) * show ip ospf neighbor detail: Showing OSPF information. (line 17) * show ip ospf neighbor INTERFACE: Showing OSPF information. (line 16) * show ip ospf neighbor INTERFACE detail: Showing OSPF information. (line 18) * show ip ospf route: Showing OSPF information. (line 41) * show ip prefix-list: Showing ip prefix-list. (line 7) * show ip prefix-list [NAME]: zebra Terminal Mode Commands. (line 23) * show ip prefix-list detail: Showing ip prefix-list. (line 31) * show ip prefix-list detail NAME: Showing ip prefix-list. (line 33) * show ip prefix-list NAME: Showing ip prefix-list. (line 10) * show ip prefix-list NAME A.B.C.D/M: Showing ip prefix-list. (line 17) * show ip prefix-list NAME A.B.C.D/M first-match: Showing ip prefix-list. (line 25) * show ip prefix-list NAME A.B.C.D/M longer: Showing ip prefix-list. (line 23) * show ip prefix-list NAME seq NUM: Showing ip prefix-list. (line 13) * show ip prefix-list summary: Showing ip prefix-list. (line 27) * show ip prefix-list summary NAME: Showing ip prefix-list. (line 29) * show ip protocol: zebra Terminal Mode Commands. (line 27) * show ip protocols: Show RIP Information. (line 17) * show ip rip: Show RIP Information. (line 9) * show ip ripng: ripngd Terminal Mode Commands. (line 7) * show ip route: zebra Terminal Mode Commands. (line 7) * show ipforward: zebra Terminal Mode Commands. (line 29) * show ipv6 ospf6 [INSTANCE_ID]: Showing OSPF6 information. (line 7) * show ipv6 ospf6 database: Showing OSPF6 information. (line 11) * show ipv6 ospf6 interface: Showing OSPF6 information. (line 15) * show ipv6 ospf6 neighbor: Showing OSPF6 information. (line 18) * show ipv6 ospf6 request-list A.B.C.D: Showing OSPF6 information. (line 21) * show ipv6 route: zebra Terminal Mode Commands. (line 19) * show ipv6 route ospf6: Showing OSPF6 information. (line 24) * show ipv6forward: zebra Terminal Mode Commands. (line 34) * show logging: Terminal Mode Commands. (line 31) * show route-map [NAME]: zebra Terminal Mode Commands. (line 25) * show version: Terminal Mode Commands. (line 27) * show zebra fpm stats: zebra Terminal Mode Commands. (line 37) * shutdown: Interface Commands. (line 9) * smux peer OID: MIB and command reference. (line 27) * smux peer OID PASSWORD: MIB and command reference. (line 30) * table TABLENO: Static Route Commands. (line 81) * terminal length <0-512>: Terminal Mode Commands. (line 17) * timers basic UPDATE TIMEOUT GARBAGE: RIP Timers. (line 7) * timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME: OSPF router. (line 91) * username USERNAME nopassword: VTY shell username. (line 7) * version VERSION: RIP Version Control. (line 20) * who: Terminal Mode Commands. (line 21) * write file: Terminal Mode Commands. (line 10) * write terminal: Terminal Mode Commands. (line 7)  File: quagga.info, Node: VTY Key Index, Next: Index, Prev: Command Index, Up: Top VTY Key Index ************* [index] * Menu: * : CLI Editing Commands. (line 11) * : CLI Advanced Commands. (line 17) * : CLI Movement Commands. (line 15) * : CLI Movement Commands. (line 11) * : CLI Advanced Commands. (line 24) * : CLI Advanced Commands. (line 21) * ?: 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-w: CLI Editing Commands. (line 20) * C-z: CLI Advanced Commands. (line 13) * M-b: CLI Movement Commands. (line 21) * M-d: CLI Editing Commands. (line 17) * M-f: CLI Movement Commands. (line 18)  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) * 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) * Linux configurations: Linux notes. (line 6) * 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) * 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) * OSPFv2: ripngd Filtering Commands. (line 14) * 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-0.99.22.4/doc/quagga.texi0000644000175000017500000000616312177450262013146 00000000000000\input texinfo @c -*- texinfo -*- @c Set variables - sourced from defines.texi @include defines.texi @c %**start of header @setchapternewpage odd @settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @setfilename quagga.info @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 @value{PACKAGE_STRING}. @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:: * Babel:: * 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 babeld.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-0.99.22.4/doc/ripd.80000644000175000017500000000524412000052240012007 00000000000000.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-0.99.22.4/doc/ripd.texi0000644000175000017500000005463212101110036012616 00000000000000@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 protocols} {} The command displays current RIP status. It includes RIP timer, filtering, version, RIP enabled interface and RIP peer inforation. @end deffn @example @group ripd> @b{show ip protocols} Routing Protocol is "rip" Sending updates every 30 seconds with +/-50%, next due in 35 seconds Timeout after 180 seconds, garbage collect after 120 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 Redistributing: kernel connected Default version control: send version 2, receive version 2 Interface Send Recv Routing for Networks: eth0 eth1 1.1.1.1 203.181.89.241 Routing Information Sources: Gateway BadPackets BadRoutes Distance Last Update @end group @end example @node RIP Debug Commands @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-0.99.22.4/doc/ripngd.80000644000175000017500000000532312000052240012332 00000000000000.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-0.99.22.4/doc/ripngd.texi0000644000175000017500000000416012000052240013132 00000000000000@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-0.99.22.4/doc/routemap.texi0000644000175000017500000001461712045513244013532 00000000000000@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 aspath @var{as_path}} {} Matches the specified @var{as_path}. @end deffn @deffn {Route-map Command} {match metric @var{metric}} {} Matches the specified @var{metric}. @end deffn @deffn {Route-map Command} {match community @var{community_list}} {} Matches the specified @var{community_list} @end deffn @node Route Map Set Command @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}} {} 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-0.99.22.4/doc/routeserver.texi0000644000175000017500000005166112000052240014244 00000000000000@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 (@pxref{fig:full-mesh}), we can convert it into a centralized scenario where each of the four establishes a single BGP peering against the Route Server (@pxref{fig: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 @image{fig-normal-processing,400pt,,Normal announcement processing} @caption{Announcement processing inside a ``normal'' BGP speaker} @end float @float Figure,fig:full-mesh @image{fig_topologies_full,120pt,,Full Mesh BGP Topology} @caption{Full Mesh} @end float @float Figure,fig:route-server @image{fig_topologies_rs,120pt,,Route Server BGP Topology} @caption{Route Server and clients} @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 @image{fig-rs-processing,450pt,,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-0.99.22.4/doc/snmp.texi0000644000175000017500000001443412177450262012656 00000000000000@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-0.99.22.4/doc/snmptrap.texi0000644000175000017500000001414012000052240013512 00000000000000@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-0.99.22.4/doc/stamp-vti0000644000175000017500000000015012211704577012643 00000000000000@set UPDATED 4 August 2013 @set UPDATED-MONTH August 2013 @set EDITION 0.99.22.4 @set VERSION 0.99.22.4 quagga-0.99.22.4/doc/texinfo.tex0000644000175000017500000116655512070614057013215 00000000000000% 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{2012-11-08.11} % % 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 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 has been our intent since Texinfo was invented.) % % 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\ptexstar=\* \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 % Since the category of space is not known, we have to be careful. \chardef\spacecat = 10 \def\spaceisspace{\catcode`\ =\spacecat} % sometimes characters are active, so we need control sequences. \chardef\ampChar = `\& \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dashChar = `\- \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\hashChar = `\# \chardef\lquoteChar= `\` \chardef\questChar = `\? \chardef\rquoteChar= `\' \chardef\semiChar = `\; \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 } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % 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 } % 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} % 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. The solution is % described on page 260 of The TeXbook. It involves outputting two % marks for the sectioning macros, one before the section break, and % one after. I won't pretend I can describe this better than DEK... \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 \noexpand\or \the\toks4 \the\toks6 \noexpand\else \the\toks8 }% } % \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\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \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{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\tt \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 \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}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\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. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#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\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \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. % \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 \prevdepth = \dimen1 \checkinserts } % % 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=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} % \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % 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 % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{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 \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 based on 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. \def\rgbDarkRed{0.50 0.09 0.12} \def\rgbBlack{0 0 0} % % k sets the color for filling (usual text, etc.); % K 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 a color that is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. \def\urlcolor{\rgbDarkRed} \def\linkcolor{\rgbDarkRed} \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 \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\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \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 (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\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\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \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. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this 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 % 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{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \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\ptexslash \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\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@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. % 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-\realdash \let_\realunder \fi \codex } } \def\codex #1{\tclose{#1}\endgroup} \def\realdash{-} \def\codedash{-\discretionary{}{}{}} \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 undesirable in % some manuals, especially if they don't have long identifiers in % general. @allowcodebreaks provides a way to control this. % \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') 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. % (This \urefnobreak definition isn't used now, leaving it for a while % for comparison.) \def\urefnobreak#1{\dourefnobreak #1,,,\finish} \def\dourefnobreak#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % This \urefbreak definition is the active one. \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}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\urefcode{#1})% DVI: 2nd arg given, show both it 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\ampChar=\active \catcode\dotChar=\active \catcode\hashChar=\active \catcode\questChar=\active \catcode\slashChar=\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\urefprestretch{\urefprebreak \hskip0pt plus.13em } \def\urefpoststretch{\urefpostbreak \hskip0pt plus.1em } % \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} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % @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{% \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 $\finishmath } \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 } } % ctrl is no longer a Texinfo command, but leave this definition for fun. \def\ctrl #1{{\tt \rawbackslash \hat}#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 } % 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. } \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. \def\bullet{$\ptexbullet$} \def\geq{\ifmmode \ge\else $\ge$\fi} \def\leq{\ifmmode \le\else $\le$\fi} \def\minus{\ifmmode -\else $-$\fi} % @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 ec* fonts (cm-super in outline format) for non-CM glyphs. \def\ecfont{% % 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 = ectt\ecsize \space at \nominalsize \else \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = ec\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 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 \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{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % 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 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}% % \vadjust{\penalty 1200}}% not good to break after first line of item. \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 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 \global\everytab={\bf}% can't use \headitemfont since the parsing differs \the\everytab % for the first item }% % % 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={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \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-\realdash \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). % \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 special treatment of `@end ifset,' call \makeond and the 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 foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @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 \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \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 define @lbrace and @rbrace commands a la @comma. \def\{{{\tt\char123}}% \def\}{{\tt\char125}}% % % I don't entirely understand this, but when an index entry is % generated from a macro call, the \endinput which \scanmacro inserts % causes processing to be prematurely terminated. This is, % apparently, because \indexsorttmp is fully expanded, and \endinput % is an expandable command. The redefinition below makes \endinput % disappear altogether for that purpose -- although logging shows that % processing continues to some further point. On the other hand, it % seems \endinput does not hurt in the printed index arg, since that % is still getting written without apparent harm. % % Sample source (mac-idx3.tex, reported by Graham Percival to % help-texinfo, 22may06): % @macro funindex {WORD} % @findex xyz % @end macro % ... % @funindex commtest % % The above is not enough to reproduce the bug, but it gives the flavor. % % Sample whatsit resulting: % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} % % So: \let\endinput = \empty % % 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\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\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. % \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\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % \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 % % Unfortunately, texindex is not prepared to handle braces in the % content at all. So for index sorting, we map @{ and @} to strings % starting with |, since that ASCII character is between ASCII { and }. \def\{{|a}% \def\lbracechar{|a}% % \def\}{|b}% \def\rbracechar{|b}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\DH{DZZ}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\TH{ZZZ}% \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{zzz}% % \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}% % \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax \else \indexlquoteignore \fi % % 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 } % Undocumented (for FSFS 2nd ed.): @set txiindexlquoteignore makes us % ignore left quotes in the sort term. {\catcode`\`=\active \gdef\indexlquoteignore{\let`=\empty}} \let\indexbackslash=0 %overridden during \printindex. \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}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % 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 } % 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 \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % 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{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % 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 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \nobreak \vskip 0pt plus 3\baselineskip \penalty 0 \vskip 0pt plus -3\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 .5\baselineskip \leftline{\secbf #1}% % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip }} % \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. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this freezes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % 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}% % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\entrybreak{\unskip\space\ignorespaces}% \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \setbox\boxA = \hbox{#1}% \ifdim\wd\boxA = 0pt \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like plain.tex's \dotfill, except uses up at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \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 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \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 \hbox to\pagewidth{\box0\hfil\box2}% } % % All done 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. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % 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 \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{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \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}} \def\chappager{\par\vfill\supereject} % 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 % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% % 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 % % 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, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% \checkenv{}% should not be in an environment. % % Switch to the right set of fonts. \csname #2fonts\endcsname \rmisbold % \def\sectionlevel{#2}% \def\temptype{#3}% % % 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. \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. \advance\hsize by -\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}\labelspace#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 \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 % \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\*=\ptexstar \let\t=\ptext \expandafter \let\csname top\endcsname=\ptextop % 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 % 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 }} \let\afterenvbreak = \aboveenvbreak % \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 % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing = t% % % 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 % \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 \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \newdimen\nonfillparindent \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % 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. \envdef\raggedright{% \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax } \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 very 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 % % 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 \def\scanmacro#1{\begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % % Undo catcode changes of \startcontents and \doprintindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. Previously, we had % \catcode`\\=\other instead. We'll see whether a problem appears % with macro expansion. --kasal, 19aug04 \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ % % ... and for \example: \spaceisspace % % The \empty here causes a following catcode 5 newline to be eaten as % part of reading whitespace after a control sequence. It does not % eat a catcode 13 newline. There's no good way to handle the two % cases (untried: maybe e-TeX's \everyeof could help, though plain TeX % would then have different behavior). See the Macro Details node in % the manual for the workaround we recommend for macros and % line-oriented commands. % \scantokens{#1\empty}% \endgroup} \def\scanexp#1{% \edef\temp{\noexpand\scanmacro{#1}}% \temp } \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 \catcode`\~=\other \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi } \def\scanargctxt{% used for copying and captions, not macros. \scanctxt \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% used for @macro definitions \scanctxt \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } \def\macroargctxt{% used when scanning invocations \scanctxt \catcode`\\=0 } % why catcode 0 for \ in the above? To recognize \\ \{ \} as "escapes" % for the single characters \ { }. Thus, we end up with the "commands" % that would be written @\ @{ @} in a Texinfo document. % % We already have @{ and @}. For @\, we define it here, and only for % this purpose, to produce a typewriter backslash (so, the @\ that we % define for @math can't be used with @macro calls): % \def\\{\normalbackslash}% % % We would like to do this for \, too, since that is what makeinfo does. % But it is not possible, because Texinfo already has a command @, for a % cedilla accent. Documents must use @comma{} instead. % % \anythingelse will almost certainly be an error of some kind. % \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 } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname#1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % For macro processing make @ a letter so that we can make Texinfo private macro names. \edef\texiatcatcode{\the\catcode`\@} \catcode `@=11\relax % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.BLAH for each BLAH % in the params list to some hook where the argument si 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). % % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. % % 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 underwhich the body was input). % % If you compile with TeX (not eTeX), and you have macros with 10 or more % arguments, you need that no macro has more than 256 arguments, otherwise an % error is produced. \def\parsemargdef#1;{% \paramno=0\def\paramlist{}% \let\hash\relax \let\xeatspaces\relax \parsemargdefxxx#1,;,% % 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. \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 {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} \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} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) % \catcode `\@\texiatcatcode \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \catcode `\@=11\relax \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}% } \def\macargexpandinbody@{% %% Define the named-macro outside of this group and then close this group. \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 } % Save the token stack pointer into macro #1 \def\texisavetoksstackpoint#1{\edef#1{\the\@cclvi}} % Restore the token stack pointer from number in macro #1 \def\texirestoretoksstackpoint#1{\expandafter\mathchardef\expandafter\@cclvi#1\relax} % newtoks that can be used non \outer . \def\texinonouternewtoks{\alloc@ 5\toks \toksdef \@cclvi} % Tailing 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}% } % This defines a Texinfo @macro. There are eight cases: recursive and % nonrecursive macros of zero, one, up to nine, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. % \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else \ifnum\paramno<10\relax % at most 9 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \else % 10 or more \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble \fi \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % at most 9 \ifnum\paramno<10\relax \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % 10 or more: \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse \fi \fi \fi} \catcode `\@\texiatcatcode\relax \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg). % \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \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 {% \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#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} % \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 % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % 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 }% \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}{}% \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{% {% \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 } % 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. {% \count1=128 \def\loop{% \catcode\count1=\other \advance\count1 by 1 \ifnum \count1<256 \loop \fi }% }% % % @ 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{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \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 % 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 % 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 % 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 \dopdfimage{#1}{#2}{#3}% \else % \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}% \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. {% \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{\begingroup \let_=\normalunderscore % normal _ character for filenames \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \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 \endgroup} % % 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 } % 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. % \parseargdef\documentencoding{% % 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 \utfeightchardefs % \else \message{Unknown document encoding #1, ignoring.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii } % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing in OT1 encoding: #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{\missingcharmsg{CENT SIGN}} \gdef^^a3{{\pounds}} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\missingcharmsg{YEN SIGN}} \gdef^^a6{\missingcharmsg{BROKEN BAR}} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\copyright} \gdef^^aa{\ordf} \gdef^^ab{\guillemetleft} \gdef^^ac{$\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{$^.$} \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 \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}% \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 \def\utfeightchardefs{% \DeclareUnicodeCharacter{00A0}{\tie} \DeclareUnicodeCharacter{00A1}{\exclamdown} \DeclareUnicodeCharacter{00A3}{\pounds} \DeclareUnicodeCharacter{00A8}{\"{ }} \DeclareUnicodeCharacter{00A9}{\copyright} \DeclareUnicodeCharacter{00AA}{\ordf} \DeclareUnicodeCharacter{00AB}{\guillemetleft} \DeclareUnicodeCharacter{00AD}{\-} \DeclareUnicodeCharacter{00AE}{\registeredsymbol} \DeclareUnicodeCharacter{00AF}{\={ }} \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} \DeclareUnicodeCharacter{00B4}{\'{ }} \DeclareUnicodeCharacter{00B8}{\cedilla{ }} \DeclareUnicodeCharacter{00BA}{\ordm} \DeclareUnicodeCharacter{00BB}{\guillemetright} \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{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{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{0118}{\ogonek{E}} \DeclareUnicodeCharacter{0119}{\ogonek{e}} \DeclareUnicodeCharacter{010A}{\dotaccent{C}} \DeclareUnicodeCharacter{010B}{\dotaccent{c}} \DeclareUnicodeCharacter{010C}{\v{C}} \DeclareUnicodeCharacter{010D}{\v{c}} \DeclareUnicodeCharacter{010E}{\v{D}} \DeclareUnicodeCharacter{0112}{\=E} \DeclareUnicodeCharacter{0113}{\=e} \DeclareUnicodeCharacter{0114}{\u{E}} \DeclareUnicodeCharacter{0115}{\u{e}} \DeclareUnicodeCharacter{0116}{\dotaccent{E}} \DeclareUnicodeCharacter{0117}{\dotaccent{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{0124}{\^H} \DeclareUnicodeCharacter{0125}{\^h} \DeclareUnicodeCharacter{0128}{\~I} \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} \DeclareUnicodeCharacter{012A}{\=I} \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} \DeclareUnicodeCharacter{012C}{\u{I}} \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} \DeclareUnicodeCharacter{0130}{\dotaccent{I}} \DeclareUnicodeCharacter{0131}{\dotless{i}} \DeclareUnicodeCharacter{0132}{IJ} \DeclareUnicodeCharacter{0133}{ij} \DeclareUnicodeCharacter{0134}{\^J} \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} \DeclareUnicodeCharacter{0139}{\'L} \DeclareUnicodeCharacter{013A}{\'l} \DeclareUnicodeCharacter{0141}{\L} \DeclareUnicodeCharacter{0142}{\l} \DeclareUnicodeCharacter{0143}{\'N} \DeclareUnicodeCharacter{0144}{\'n} \DeclareUnicodeCharacter{0147}{\v{N}} \DeclareUnicodeCharacter{0148}{\v{n}} \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{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{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{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{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{ }} \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} \DeclareUnicodeCharacter{2013}{--} \DeclareUnicodeCharacter{2014}{---} \DeclareUnicodeCharacter{2018}{\quoteleft} \DeclareUnicodeCharacter{2019}{\quoteright} \DeclareUnicodeCharacter{201A}{\quotesinglbase} \DeclareUnicodeCharacter{201C}{\quotedblleft} \DeclareUnicodeCharacter{201D}{\quotedblright} \DeclareUnicodeCharacter{201E}{\quotedblbase} \DeclareUnicodeCharacter{2022}{\bullet} \DeclareUnicodeCharacter{2026}{\dots} \DeclareUnicodeCharacter{2039}{\guilsinglleft} \DeclareUnicodeCharacter{203A}{\guilsinglright} \DeclareUnicodeCharacter{20AC}{\euro} \DeclareUnicodeCharacter{2192}{\expansion} \DeclareUnicodeCharacter{21D2}{\result} \DeclareUnicodeCharacter{2212}{\minus} \DeclareUnicodeCharacter{2217}{\point} \DeclareUnicodeCharacter{2261}{\equiv} }% end of \utfeightchardefs % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % 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} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \let\realunder=_ % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} % 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. % 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). It seems better for @backslashchar{} to always % print a typewriter backslash, 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@normalbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} @let@backslashchar = @normalbackslash % @backslashchar{} is for user documents. % On startup, @fixbackslash assigns: % @let \ = @normalbackslash % \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 `\'. % @def@normalturnoffactive{% @let"=@normaldoublequote @let$=@normaldollar %$ font-lock fix @let+=@normalplus @let<=@normalless @let>=@normalgreater @let\=@normalbackslash @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let~=@normaltilde @markupsetuplqdefault @markupsetuprqdefault @unsepspaces } % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\' in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % 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" @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 quagga-0.99.22.4/doc/version.texi0000644000175000017500000000015012211704577013354 00000000000000@set UPDATED 4 August 2013 @set UPDATED-MONTH August 2013 @set EDITION 0.99.22.4 @set VERSION 0.99.22.4 quagga-0.99.22.4/doc/vtysh.10000644000175000017500000000533112000052240012214 00000000000000.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). .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-0.99.22.4/doc/vtysh.texi0000644000175000017500000000455612000052240013035 00000000000000@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-0.99.22.4/doc/watchquagga.80000644000175000017500000001550012177450262013366 00000000000000.\" 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-0.99.22.4/doc/zebra.80000644000175000017500000000670412211704467012201 00000000000000.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 doesn't allow to increase it over 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 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-0.99.22.4/fpm/0000755000175000017500000000000012211704576011074 500000000000000quagga-0.99.22.4/fpm/fpm.h0000644000175000017500000001577612177450262011770 00000000000000/* * 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. */ #define FPM_DEFAULT_PORT 2620 /* * Largest message that can be sent to or received from the FPM. */ #define FPM_MAX_MSG_LEN 4096 /* * 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. * * Note that msg_len is rounded up to make sure that message is at * the desired alignment. This means that some payloads may need * padding at the end. */ uint16_t msg_len; } fpm_msg_hdr_t; /* * 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. */ FPM_MSG_TYPE_NETLINK = 1, } 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. */ 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 (fpm_msg_align (sizeof (fpm_msg_hdr_t))) /* * 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 fpm_msg_align (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; if (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; } #endif /* _FPM_H */ quagga-0.99.22.4/install-sh0000755000175000017500000003325512070614057012243 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # 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. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # 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_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' 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 no_target_directory= 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 *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done 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 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 -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` 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 eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob 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` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob 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-0.99.22.4/isisd/0000755000175000017500000000000012211704577011426 500000000000000quagga-0.99.22.4/isisd/AUTHORS0000644000175000017500000000022712177450262012417 00000000000000Sampo Saaristo Ofer Wald Hannes Gredler Subbaiah Venkata quagga-0.99.22.4/isisd/Makefile.am0000644000175000017500000000230512177450262013402 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -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 = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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_route.c isis_routemap.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_route.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-0.99.22.4/isisd/Makefile.in0000644000175000017500000007205712211704501013411 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = README $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp AUTHORS 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru 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_route.$(OBJEXT) \ isis_routemap.$(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_route.$(OBJEXT) \ isis_routemap.$(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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) DIST_SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) RECURSIVE_TARGETS = all-recursive check-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 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=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) 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@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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_route.c isis_routemap.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_route.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 .PRECIOUS: 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) -rm -f libisis.a $(libisis_a_AR) libisis.a $(libisis_a_OBJECTS) $(libisis_a_LIBADD) $(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) $(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_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_tlv.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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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. $(RECURSIVE_TARGETS) $(RECURSIVE_CLEAN_TARGETS): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ 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" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ done ctags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ done cscopelist-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) cscopelist); \ done ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) 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; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) \ cscopelist-recursive ctags-recursive install-am install-strip \ tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am check check-am clean clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS cscopelist \ cscopelist-recursive ctags ctags-recursive 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-recursive \ uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/isisd/README0000644000175000017500000000006212000052240012177 00000000000000Constraints o Maximum number of interfaces 255 quagga-0.99.22.4/isisd/dict.c0000644000175000017500000010473212177450262012444 00000000000000/* * 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-0.99.22.4/isisd/dict.h0000644000175000017500000000773712177450262012460 00000000000000/* * 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-0.99.22.4/isisd/include-netbsd/0000755000175000017500000000000012211704577014326 500000000000000quagga-0.99.22.4/isisd/include-netbsd/clnp.h0000644000175000017500000005051512000052240015334 00000000000000/* $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-0.99.22.4/isisd/include-netbsd/esis.h0000644000175000017500000001412112000052240015334 00000000000000/* $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-0.99.22.4/isisd/include-netbsd/iso.h0000644000175000017500000001616612000052240015176 00000000000000/* $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 */ #ifdef SUNOS_5 #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-0.99.22.4/isisd/isis_adjacency.c0000644000175000017500000003417712177450262014476 00000000000000/* * 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 (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 (u_char * id, 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 (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 (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 = adj->sysid ? sysid_print (adj->sysid) : "unknown"; 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", adj->sysid ? sysid_print (adj->sysid) : "unknown", 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 if (adj->sysid) { vty_out (vty, " %-20s", sysid_print (adj->sysid)); } else { vty_out (vty, " unknown "); } 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, "%-9lu", 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 (!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-0.99.22.4/isisd/isis_adjacency.h0000644000175000017500000000757712177450262014507 00000000000000/* * 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 (u_char * sysid, struct list *adjdb); struct isis_adjacency *isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb); struct isis_adjacency *isis_new_adj (u_char * id, 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-0.99.22.4/isisd/isis_bpf.c0000644000175000017500000002170412177450262013314 00000000000000/* * 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 "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; int written, 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 %lu 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); /* * 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); return ISIS_OK; } int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_BPF */ quagga-0.99.22.4/isisd/isis_circuit.c0000644000175000017500000023434212177450262014213 00000000000000/* * 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 "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" /* * 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->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC; circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; } 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; /* * The level for the circuit is same as for the area, unless configured * otherwise. */ if (area->is_type != IS_LEVEL_1_AND_2 && area->is_type != circuit->is_type) zlog_warn ("circut %s is_type %d mismatch with area %s is_type %d", circuit->interface->name, circuit->is_type, circuit->area->area_tag, 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); } 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; } 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); 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); } 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); } 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(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; } 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); } } } } } } 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->circ_type == CIRCUIT_T_BROADCAST) { /* * Get the Hardware Address */ #ifdef HAVE_STRUCT_SOCKADDR_DL #ifndef SUNOS_5 if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) zlog_warn ("unsupported link layer"); else memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), ETH_ALEN); #endif #else 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 */ #endif /* HAVE_STRUCT_SOCKADDR_DL */ circuit->u.bc.adjdb[0] = list_new (); circuit->u.bc.adjdb[1] = list_new (); if (circuit->area->min_bcast_mtu == 0 || ISO_MTU (circuit) < circuit->area->min_bcast_mtu) circuit->area->min_bcast_mtu = ISO_MTU (circuit); /* * 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 */ if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); #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]); } 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) { 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->metrics[0].metric_default); 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->metrics[1].metric_default); 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) { struct listnode *node; struct prefix *ip_addr; u_char buf[BUFSIZ]; 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); } } 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; } DEFUN (ip_router_isis, ip_router_isis_cmd, "ip 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 isis_circuit *circuit; struct interface *ifp; struct isis_area *area; ifp = (struct interface *) vty->index; assert (ifp); /* Prevent more than one area per circuit */ circuit = circuit_scan_by_ifp (ifp); if (circuit) { if (circuit->ip_router == 1) { if (strcmp (circuit->area->area_tag, argv[0])) { vty_out (vty, "ISIS circuit is already defined on %s%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } return CMD_SUCCESS; } } if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = vty->index; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); isis_circuit_if_bind (circuit, ifp); circuit->ip_router = 1; area->ip_circuits++; circuit_update_nlpids (circuit); vty->node = INTERFACE_NODE; vty->index = ifp; return CMD_SUCCESS; } DEFUN (no_ip_router_isis, no_ip_router_isis_cmd, "no ip 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; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = isis_area_lookup (argv[0]); 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; } circuit->ip_router = 0; area->ip_circuits--; #ifdef HAVE_IPV6 if (circuit->ipv6_router == 0) #endif isis_csm_state_change (ISIS_DISABLE, circuit, area); return CMD_SUCCESS; } #ifdef HAVE_IPV6 DEFUN (ipv6_router_isis, ipv6_router_isis_cmd, "ipv6 router isis WORD", "IPv6 interface subcommands\n" "IPv6 Router interface commands\n" "IS-IS Routing for IPv6\n" "Routing process tag\n") { struct isis_circuit *circuit; struct interface *ifp; struct isis_area *area; ifp = (struct interface *) vty->index; assert (ifp); /* Prevent more than one area per circuit */ circuit = circuit_scan_by_ifp (ifp); if (circuit) { if (circuit->ipv6_router == 1) { if (strcmp (circuit->area->area_tag, argv[0])) { vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } return CMD_SUCCESS; } } if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = vty->index; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); isis_circuit_if_bind (circuit, ifp); circuit->ipv6_router = 1; area->ipv6_circuits++; circuit_update_nlpids (circuit); vty->node = INTERFACE_NODE; vty->index = ifp; return CMD_SUCCESS; } DEFUN (no_ipv6_router_isis, no_ipv6_router_isis_cmd, "no ipv6 router isis WORD", NO_STR "IPv6 interface subcommands\n" "IPv6 Router interface commands\n" "IS-IS Routing for IPv6\n" "Routing process tag\n") { struct interface *ifp; struct isis_area *area; struct listnode *node; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = isis_area_lookup (argv[0]); 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; } circuit->ipv6_router = 0; area->ipv6_circuits--; if (circuit->ip_router == 0) isis_csm_state_change (ISIS_DISABLE, circuit, area); return CMD_SUCCESS; } #endif /* HAVE_IPV6 */ 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; if (circuit->is_passive == 1) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->is_passive = 1; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->is_passive = 1; isis_csm_state_change (ISIS_ENABLE, circuit, area); } 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 interface *ifp; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } /* FIXME: what is wrong with circuit = ifp->info ? */ circuit = circuit_scan_by_ifp (ifp); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } if (if_is_loopback(ifp)) { vty_out (vty, "Can't set no passive for loopback interface%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if (circuit->is_passive == 0) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->is_passive = 0; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->is_passive = 0; isis_csm_state_change (ISIS_ENABLE, circuit, area); } 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 circuit_type; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit_type = string2circuit_t (argv[0]); if (!circuit_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 != circuit_type) { vty_out (vty, "Invalid circuit level for area %s.%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_event_circuit_type_change (circuit, circuit_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 circuit_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) circuit_type = circuit->area->is_type; else circuit_type = IS_LEVEL_1_AND_2; isis_event_circuit_type_change (circuit, circuit_type); return CMD_SUCCESS; } DEFUN (isis_passwd_md5, isis_passwd_md5_cmd, "isis password md5 WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "Authentication type\n" "Circuit password\n") { int len; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; strncpy ((char *)circuit->passwd.passwd, argv[0], 255); return CMD_SUCCESS; } DEFUN (isis_passwd_clear, isis_passwd_clear_cmd, "isis password clear WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "Authentication type\n" "Circuit password\n") { int len; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)circuit->passwd.passwd, argv[0], 255); 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; memset (&circuit->passwd, 0, sizeof (struct isis_passwd)); return CMD_SUCCESS; } 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; } circuit->te_metric[0] = met; circuit->te_metric[1] = met; circuit->metrics[0].metric_default = met; circuit->metrics[1].metric_default = met; if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); 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; circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); 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; } circuit->te_metric[0] = met; circuit->metrics[0].metric_default = met; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); 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; circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); 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; } circuit->te_metric[1] = met; circuit->metrics[1].metric_default = met; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); 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; circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); 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") struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; 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; /* RFC5309 section 4 */ if (circuit->circ_type == CIRCUIT_T_P2P) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->circ_type = CIRCUIT_T_P2P; circuit->circ_type_config = CIRCUIT_T_P2P; } else { struct isis_area *area = circuit->area; if (!if_is_broadcast (circuit->interface)) { vty_out (vty, "isis network point-to-point " "is valid only on broadcast interfaces%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->circ_type = CIRCUIT_T_P2P; circuit->circ_type_config = CIRCUIT_T_P2P; isis_csm_state_change (ISIS_ENABLE, circuit, area); } 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; /* RFC5309 section 4 */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->circ_type = CIRCUIT_T_BROADCAST; circuit->circ_type_config = CIRCUIT_T_BROADCAST; } else { struct isis_area *area = circuit->area; if (circuit->interface && !if_is_broadcast (circuit->interface)) { vty_out (vty, "no isis network point-to-point " "is valid only on broadcast interfaces%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->circ_type = CIRCUIT_T_BROADCAST; circuit->circ_type_config = CIRCUIT_T_BROADCAST; isis_csm_state_change (ISIS_ENABLE, circuit, area); } return CMD_SUCCESS; } 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_init (); 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); 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_passwd_clear_cmd); install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_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 (INTERFACE_NODE, &isis_network_cmd); install_element (INTERFACE_NODE, &no_isis_network_cmd); #ifdef HAVE_IPV6 install_element (INTERFACE_NODE, &ipv6_router_isis_cmd); install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd); #endif } quagga-0.99.22.4/isisd/isis_circuit.h0000644000175000017500000001426612177450262014221 00000000000000/* * 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 #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 * diffrenciated 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 */ struct metric metrics[2]; /* l1XxxMetric */ u_int32_t te_metric[2]; 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); #endif /* _ZEBRA_ISIS_CIRCUIT_H */ quagga-0.99.22.4/isisd/isis_common.h0000644000175000017500000000332012177450262014034 00000000000000/* * 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-0.99.22.4/isisd/isis_constants.h0000644000175000017500000001144212177450262014564 00000000000000/* * 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 #define RECEIVE_LSP_BUFFER_SIZE 1492 /* * 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-0.99.22.4/isisd/isis_csm.c0000644000175000017500000001303712177450262013327 00000000000000/* * 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) { isis_circuit_if_del (circuit, (struct interface *) arg); 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-0.99.22.4/isisd/isis_csm.h0000644000175000017500000000301712000052240013304 00000000000000/* * 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-0.99.22.4/isisd/isis_dlpi.c0000644000175000017500000004000612177450262013471 00000000000000/* * 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 "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 void 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; 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 */ if (putmsg (fd, ctlptr, dataptr, flags) == -1) zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); } 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 < 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 < 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 < 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 < 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 > 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, 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: %d", __func__, circuit->interface->name, 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 < 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 > 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; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; if (buflen > sizeof (sock_buff)) { zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu 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)); dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, sock_buff, buflen, 0); return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_DLPI */ quagga-0.99.22.4/isisd/isis_dr.c0000644000175000017500000002376412177450262013162 00000000000000/* * 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-0.99.22.4/isisd/isis_dr.h0000644000175000017500000000277112000052240013135 00000000000000/* * 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-0.99.22.4/isisd/isis_dynhn.c0000644000175000017500000001031712177450262013663 00000000000000/* * 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 (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 (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 (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-0.99.22.4/isisd/isis_dynhn.h0000644000175000017500000000274412177450262013675 00000000000000/* * 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 (u_char * id, struct hostname *hostname, int level); void isis_dynhn_remove (u_char * id); struct isis_dynhn *dynhn_find_by_id (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-0.99.22.4/isisd/isis_events.c0000644000175000017500000002425512177450262014055 00000000000000/* * 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 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 */ THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); } void isis_event_system_type_change (struct isis_area *area, int newtype) { 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 (newtype)); if (area->is_type == newtype) return; /* No change */ switch (area->is_type) { case IS_LEVEL_1: if (newtype == 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 (newtype == IS_LEVEL_1) area_resign_level (area, IS_LEVEL_2); else area_resign_level (area, IS_LEVEL_1); break; case IS_LEVEL_2: if (newtype == 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 = newtype; /* 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_event_circuit_type_change (circuit, newtype); } spftree_area_init (area); if (newtype & IS_LEVEL_1) lsp_generate (area, IS_LEVEL_1); if (newtype & IS_LEVEL_2) lsp_generate (area, IS_LEVEL_2); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); 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->u.bc.run_dr_elect[idx] = 0; list_delete (circuit->u.bc.lan_neighs[idx]); circuit->u.bc.lan_neighs[idx] = NULL; } return; } void isis_event_circuit_type_change (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; } 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-0.99.22.4/isisd/isis_events.h0000644000175000017500000000341712177450262014057 00000000000000/* * 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 area */ void isis_event_system_type_change (struct isis_area *area, int newtype); /* * 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-0.99.22.4/isisd/isis_flags.c0000644000175000017500000000417712177450262013646 00000000000000/* * 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-0.99.22.4/isisd/isis_flags.h0000644000175000017500000000413612177450262013646 00000000000000/* * 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-0.99.22.4/isisd/isis_lsp.c0000644000175000017500000023116512177450262013347 00000000000000/* * 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 * * 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 "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 "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" #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; 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; } if (ntohl (seq_num) >= ntohl (lsp->lsp_header->seq_num)) { 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, (caddr_t) &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) { 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; 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 (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)); if (!lsp) { /* FIXME: set lspdbol bit */ zlog_warn ("lsp_new(): out of memory"); return NULL; } /* FIXME: Should be minimal mtu? */ lsp->pdu = stream_new (1500); 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); } /* 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; } 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 */ 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; assert (area->lsp_gen_interval[level - 1] < refresh_time); 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 (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, lsp_bits_generate (level, area->overload_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; } /* * 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; /* * 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->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0) { 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) { lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct hostname)); memcpy (lsp->tlv_data.hostname->name, unix_hostname (), strlen (unix_hostname ())); lsp->tlv_data.hostname->namelen = strlen (unix_hostname ()); tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); } /* 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) { 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->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); } } 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 */ /* * Then build lists of tlvs related to circuits */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) { if (circuit->state != C_STATE_UP) continue; /* * Add IPv4 internal reachability of this circuit */ if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) { 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 = circuit->metrics[level - 1]; masklen2ip (ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr = ((ipreach->mask.s_addr) & (ipv4->prefix.s_addr)); 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->metrics[level - 1].metric_default); 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); 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->metrics[level - 1].metric_default); 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); 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 = circuit->metrics[level - 1]; if (!memcmp (is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) XFREE (MTYPE_ISIS_TLV, is_neigh); else 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)); 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->metrics[level - 1].metric_default; 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); else listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } 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 = circuit->metrics[level - 1]; listnode_add (tlv_data.is_neighs, is_neigh); } 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); listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } break; case CIRCUIT_T_LOOPBACK: break; default: zlog_warn ("lsp_area_create: unknown circuit type"); } } 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_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); } /* 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 (lspid, rem_lifetime, seq_num, area->is_type | area->overload_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); lsp_set_all_srmflags (newlsp); refresh_time = lsp_refresh_time (newlsp, rem_lifetime); THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); 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); } 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); 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); /* 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); 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); } 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; 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; 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; struct listnode *cnode; struct isis_circuit *circuit; int lvl; if (area == NULL) return ISIS_ERROR; 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; if (area->lsp_regenerate_pending[lvl - 1]) continue; lsp = lsp_search (id, area->lspdb[lvl - 1]); if (!lsp) continue; /* * Throttle avoidance */ THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]); diff = now - lsp->last_generated; if (diff < area->lsp_gen_interval[lvl - 1]) { area->lsp_regenerate_pending[lvl - 1] = 1; if (lvl == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], lsp_l1_refresh, area, area->lsp_gen_interval[lvl - 1] - diff); else if (lvl == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], lsp_l2_refresh, area, area->lsp_gen_interval[lvl - 1] - diff); } else { lsp_regenerate (area, lvl); } } 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; lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); /* * 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); } 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); } 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); } 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); } } 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); } } } list_delete (adj_list); /* 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 (lsp_id, rem_lifetime, 1, circuit->area->is_type, 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); 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; int lvl; if (circuit == NULL || circuit->circ_type != CIRCUIT_T_BROADCAST || circuit->state != C_STATE_UP) return ISIS_OK; 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++) { if (!((level & lvl) && (circuit->is_type & lvl))) continue; if (circuit->u.bc.is_dr[lvl - 1] == 0 || circuit->lsp_regenerate_pending[lvl - 1]) continue; lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]); if (!lsp) continue; /* * Throttle avoidance */ 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]) { circuit->lsp_regenerate_pending[lvl - 1] = 1; if (lvl == IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], lsp_l1_refresh_pseudo, circuit, circuit->area->lsp_gen_interval[lvl - 1] - diff); else if (lvl == IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], lsp_l2_refresh_pseudo, circuit, circuit->area->lsp_gen_interval[lvl - 1] - diff); } else { lsp_regenerate_pseudo (circuit, lvl); } } 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 (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 = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? IS_LEVEL_1 : IS_LEVEL_2; /* FIXME: Should be minimal mtu? */ lsp->pdu = stream_new (1500); 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, refresh_time; 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); 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 (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit, 0, 1); if (!lsp) return; lsp->area = area; 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-0.99.22.4/isisd/isis_lsp.h0000644000175000017500000001146612177450262013354 00000000000000/* * 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 (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 (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-0.99.22.4/isisd/isis_main.c0000644000175000017500000001772712211704467013501 00000000000000/* * 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 "zclient.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_zebra.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 http://bugzilla.quagga.net\n", progname); } 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; struct thread thread; 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 */ srand (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(); isis_init (); isis_circuit_init (); isis_spf_cmds_init (); /* create the global 'isis' instance */ isis_new (1); isis_zebra_init (); sort_node (); /* 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); /* 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. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ exit (0); } quagga-0.99.22.4/isisd/isis_misc.c0000644000175000017500000003035412177450262013501 00000000000000/* * 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 (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 (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 (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 (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 * rand ()) / (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 (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-0.99.22.4/isisd/isis_misc.h0000644000175000017500000000503712177450262013506 00000000000000/* * 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 (u_char *, int len); const char *sysid_print (u_char *); const char *snpa_print (u_char *); const char *rawlspid_print (u_char *); const char *time2string (u_int32_t); /* typedef struct nlpids nlpids; */ char *nlpid2string (struct nlpids *); const char *print_sys_hostname (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-0.99.22.4/isisd/isis_network.h0000644000175000017500000000265612000052240014223 00000000000000/* * 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-0.99.22.4/isisd/isis_pdu.c0000644000175000017500000026025612177450262013344 00000000000000/* * 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" #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 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, (caddr_t) &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; 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) == 0 || ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) { zlog_warn ("ISIS-Adj: No usable IP interface addresses " "in LAN IIH from %s\n", circuit->interface->name); 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 (!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; 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); #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; } adj->circuit_t = hdr->circuit_t; 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, 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; 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) == 0 || ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) { zlog_debug ("ISIS-Adj: No usable IP interface addresses " "in LAN IIH from %s\n", circuit->interface->name); retval = ISIS_WARNING; goto out; } 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 %ld", 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, 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; 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.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); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* v */ ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */ /* 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 (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, 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 CSNP 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 (entry->lsp_id, ntohs (entry->rem_lifetime), 0, 0, entry->checksum, level); lsp->area = circuit->area; 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, 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, 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); } /* * Process ISH * ISO - 10589 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00 * 0x03 0x00 0x81 0x01 0xcc */ static int process_is_hello (struct isis_circuit *circuit) { struct isis_adjacency *adj; int retval = ISIS_OK; u_char neigh_len; u_char *sysid; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd ISH 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)); } /* In this point in time we are not yet able to handle is_hellos * on lan - Sorry juniper... */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) return retval; neigh_len = stream_getc (circuit->rcv_stream); sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN; adj = circuit->u.p2p.neighbor; if (!adj) { /* 8.2.2 */ adj = isis_new_adj (sysid, NULL, 0, circuit); if (adj == NULL) return ISIS_ERROR; isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; circuit->u.p2p.neighbor = adj; } /* 8.2.2 a) */ if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) { /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */ /* 8.2.2 a) 2) delete the adj */ XFREE (MTYPE_ISIS_ADJACENCY, adj); /* 8.2.2 a) 3) create a new adj */ adj = isis_new_adj (sysid, NULL, 0, circuit); if (adj == NULL) return ISIS_ERROR; /* 8.2.2 a) 3) i */ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); /* 8.2.2 a) 3) ii */ adj->sys_type = ISIS_SYSTYPE_UNKNOWN; /* 8.2.2 a) 4) quite meaningless */ } /* 8.2.2 b) ignore on condition */ if ((adj->adj_state == ISIS_ADJ_INITIALIZING) && (adj->sys_type == ISIS_SYSTYPE_IS)) { /* do nothing */ } else { /* 8.2.2 c) respond with a p2p IIH */ send_hello (circuit, 1); } /* 8.2.2 d) type is IS */ adj->sys_type = ISIS_SYSTYPE_IS; /* 8.2.2 e) FIXME: Circuit type of? */ return retval; } /* * 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); if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else stream_reset (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; if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else stream_reset (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]; unsigned long 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; } if (!circuit->snd_stream) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (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, (caddr_t) &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): Sent L%d LAN IIH on %s, length %ld", circuit->area->area_tag, level, circuit->interface->name, /* FIXME: use %z when we stop supporting old compilers. */ length); } else { zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld", circuit->area->area_tag, circuit->interface->name, /* FIXME: use %z when we stop supporting old compilers. */ 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->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->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; if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (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, (caddr_t) &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): Sent L%d CSNP on %s, length %ld", 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; if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (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, (caddr_t) &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): Sent L%d PSNP on %s, length %ld", 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 retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); if (circuit->state != C_STATE_UP || circuit->is_passive == 1) { return retval; } 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 retval; } lsp = listgetdata(node); /* * Do not send if levels do not match */ if (!(lsp->level & circuit->is_type)) { list_delete_node (circuit->lsp_queue, node); return retval; } /* * Do not send if we do not have adjacencies in state up on the circuit */ if (circuit->upadjcount[lsp->level - 1] == 0) { list_delete_node (circuit->lsp_queue, node); return retval; } /* 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): Sent 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)); } retval = circuit->tx (circuit, lsp->level); if (retval != ISIS_OK) { zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed", circuit->area->area_tag, lsp->level, circuit->interface->name); return retval; } /* * If the sending succeeded, we can del the lsp from circuits * lsp_queue */ 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); /* * On broadcast circuits also the SRMflag can be cleared */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) 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; if (!circuit->snd_stream) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (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-0.99.22.4/isisd/isis_pdu.h0000644000175000017500000002446012177450262013344 00000000000000/* * 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-0.99.22.4/isisd/isis_pfpacket.c0000644000175000017500000002616112177450262014344 00000000000000/* * 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 "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 char discard_buff[8192]; static char 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) { zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, " "recvfrom(): %s", circuit->interface->name, circuit->fd, bytesread, safe_strerror (errno)); /* 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 */ int written = 1; 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); written = sendmsg (circuit->fd, &msg, 0); return ISIS_OK; } int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { int written = 1; 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; 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); written = sendto (circuit->fd, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream), 0, (struct sockaddr *) &sa, sizeof (struct sockaddr_ll)); return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */ quagga-0.99.22.4/isisd/isis_route.c0000644000175000017500000004406012177450262013703 00000000000000/* * 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, unsigned int 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)); if (!nexthop) { zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!"); } 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, unsigned int 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, unsigned int ifindex) { struct isis_nexthop6 *nexthop6; nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6)); if (!nexthop6) { zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!"); } 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, unsigned int 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, unsigned int 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 (!rinfo) { zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!"); return NULL; } 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 (!rinfo_new) { zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", area->area_tag); return NULL; } 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 /* 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-0.99.22.4/isisd/isis_route.h0000644000175000017500000000442012177450262013704 00000000000000/* * 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 { unsigned int ifindex; struct in6_addr ip6; struct in6_addr router_address6; unsigned int lock; }; #endif /* HAVE_IPV6 */ struct isis_nexthop { unsigned int 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-0.99.22.4/isisd/isis_routemap.c0000644000175000017500000000502312177450262014375 00000000000000/* * IS-IS Rout(e)ing protocol - isis_routemap.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 "linklist.h" #include "vty.h" #include "log.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "if.h" #include "table.h" #include "routemap.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" extern struct isis *isis; /* * Prototypes. */ void isis_route_map_upd(const char *); void isis_route_map_event(route_map_event_t, const char *); void isis_route_map_init(void); void isis_route_map_upd (const char *name) { int i = 0; if (!isis) return; for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { if (isis->rmap[i].name) isis->rmap[i].map = route_map_lookup_by_name (isis->rmap[i].name); else isis->rmap[i].map = NULL; } /* FIXME: do the address family sub-mode AF_INET6 here ? */ } void isis_route_map_event (route_map_event_t event, const char *name) { int type; if (!isis) return; for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (isis->rmap[type].name && isis->rmap[type].map && !strcmp (isis->rmap[type].name, name)) { isis_distribute_list_update (type); } } } void isis_route_map_init (void) { route_map_init (); route_map_init_vty (); route_map_add_hook (isis_route_map_upd); route_map_delete_hook (isis_route_map_upd); route_map_event_hook (isis_route_map_event); } quagga-0.99.22.4/isisd/isis_spf.c0000644000175000017500000013314212177450262013335 00000000000000/* * 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)); if (vertex == NULL) { zlog_err ("isis_vertex_new Out of memory!"); return NULL; } 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 unknow 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)", 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 %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_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 %d sec from now", area->area_tag, level, 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); install_element (ENABLE_NODE, &show_isis_topology_cmd); install_element (ENABLE_NODE, &show_isis_topology_l1_cmd); install_element (ENABLE_NODE, &show_isis_topology_l2_cmd); } quagga-0.99.22.4/isisd/isis_spf.h0000644000175000017500000000557712177450262013354 00000000000000/* * 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-0.99.22.4/isisd/isis_tlv.c0000644000175000017500000010614112177450262013351 00000000000000/* * 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" 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 */ u_char virtual; 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 | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ virtual = *pnt; /* FIXME: what is the use for this? */ 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 += 11; pnt += 11; /* FIXME - subtlvs are handled here, for now we skip */ 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); retval = ISIS_WARNING; 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: This will be wrong if we are going to add TE sub TLVs. */ if (pos - value + IS_NEIGHBOURS_LEN > 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; /* Sub TLVs length. */ *pos = 0; pos++; } 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; int retval; 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); } int tlv_add_ipv4_reachs (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 (IPV4_INT_REACHABILITY, 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 (IPV4_INT_REACHABILITY, pos - value, value, 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-0.99.22.4/isisd/isis_tlv.h0000644000175000017500000002504312177450262013357 00000000000000/* * 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 * TE 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 * 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 - - - draft-ietf-isis-caps * * * IS Reachability sub-TLVs we (should) support. * ____________________________________________________________________________ * 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 * * * 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 AUTH_INFO_HDRLEN 3 #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 /* struct for neighbor */ struct is_neigh { struct metric metrics; u_char neigh_id[ISIS_SYS_ID_LEN + 1]; }; /* struct for te is neighbor */ struct te_is_neigh { u_char neigh_id[ISIS_SYS_ID_LEN + 1]; u_char te_metric[3]; u_char sub_tlvs_length; }; /* 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 0 #define DIRECTION_DOWN 1 #define CTRL_INFO_DISTRIBUTION 0x40 #define DISTRIBUTION_INTERNAL 0 #define DISTRIBUTION_EXTERNAL 1 #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_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-0.99.22.4/isisd/isis_zebra.c0000644000175000017500000003742212177450262013654 00000000000000/* * IS-IS Rout(e)ing protocol - isis_zebra.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 "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 "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" 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) { struct isis_area *area; struct listnode *node; struct prefix router_id; 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) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); 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) { struct interface *ifp; struct stream *s; s = zclient->ibuf; ifp = zebra_interface_state_read (s); 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) { struct interface *ifp; ifp = zebra_interface_state_read (zclient->ibuf); 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) { struct interface *ifp; struct isis_circuit *circuit; ifp = zebra_interface_state_read (zclient->ibuf); 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) { struct connected *c; struct prefix *p; char buf[BUFSIZ]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); 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) { 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); 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 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 (zclient->redist[ZEBRA_ROUTE_ISIS]) { 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); /* 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 (zclient->redist[ZEBRA_ROUTE_ISIS]) { 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 void isis_zebra_route_add_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv6 api; struct in6_addr **nexthop_list; unsigned int *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.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 = (unsigned int *) 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; unsigned int *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.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 = (unsigned int *) 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 (!zclient->redist[ZEBRA_ROUTE_ISIS]) 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) { struct stream *stream; struct zapi_ipv4 api; struct prefix_ipv4 p; unsigned long ifindex; struct in_addr nexthop; stream = zclient->ibuf; memset (&p, 0, sizeof (struct prefix_ipv4)); ifindex = 0; api.type = stream_getc (stream); api.flags = stream_getc (stream); api.message = stream_getc (stream); p.family = AF_INET; 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); 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); else api.metric = 0; if (command == ZEBRA_IPV4_ROUTE_ADD) { if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("IPv4 Route add from Z"); } return 0; } #ifdef HAVE_IPV6 static int isis_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { return 0; } #endif #define ISIS_TYPE_IS_REDISTRIBUTED(T) \ T == ZEBRA_ROUTE_MAX ? zclient->default_information : zclient->redist[type] int isis_distribute_list_update (int routetype) { return 0; } #if 0 /* Not yet. */ static int isis_redistribute_default_set (int routetype, int metric_type, int metric_value) { return 0; } #endif /* 0 */ void isis_zebra_init () { zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_ISIS); 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->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-0.99.22.4/isisd/isis_zebra.h0000644000175000017500000000235512000052240013631 00000000000000/* * 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 (void); void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info); int isis_distribute_list_update (int routetype); #endif /* _ZEBRA_ISIS_ZEBRA_H */ quagga-0.99.22.4/isisd/isisd.c0000644000175000017500000025543012177450262012636 00000000000000/* * 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" #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; */ } 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; #ifdef TOPOLOGY_GENERATE memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); #endif /* TOPOLOGY_GENERATE */ /* FIXME: Think of a better way... */ area->min_bcast_mtu = 1497; 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 */ 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); } DEFUN (show_debugging, show_debugging_cmd, "show debugging", SHOW_STR "State of each debugging option\n") { 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++; } 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 (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 : %u msec%s", 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]); } DEFUN (area_passwd_md5, area_passwd_md5_cmd, "area-password md5 WORD", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->area_passwd.len = (u_char) len; area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; strncpy ((char *)area->area_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (area_passwd_md5, area_passwd_md5_snpauth_cmd, "area-password md5 WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\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 (area_passwd_clear, area_passwd_clear_cmd, "area-password clear WORD", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->area_passwd.len = (u_char) len; area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->area_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (area_passwd_clear, area_passwd_clear_snpauth_cmd, "area-password clear WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\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", NO_STR "Configure the authentication password for an area\n") { struct isis_area *area; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } memset (&area->area_passwd, 0, sizeof (struct isis_passwd)); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } DEFUN (domain_passwd_md5, domain_passwd_md5_cmd, "domain-password md5 WORD", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->domain_passwd.len = (u_char) len; area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (domain_passwd_md5, domain_passwd_md5_snpauth_cmd, "domain-password md5 WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n"); DEFUN (domain_passwd_clear, domain_passwd_clear_cmd, "domain-password clear WORD", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->domain_passwd.len = (u_char) len; area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (domain_passwd_clear, domain_passwd_clear_snpauth_cmd, "domain-password clear WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain 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_domain_passwd, no_domain_passwd_cmd, "no domain-password", NO_STR "Set the authentication password for a routing domain\n") { struct isis_area *area; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } memset (&area->domain_passwd, 0, sizeof (struct isis_passwd)); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } 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_event_system_type_change (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_event_system_type_change (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") 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; int ret; area = vty->index; assert (area); if (strncmp (argv[0], "w", 1) == 0) { area->newmetric = 1; area->oldmetric = 0; } else { ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; if (strncmp (argv[0], "t", 1) == 0) { area->newmetric = 1; area->oldmetric = 1; } else if (strncmp (argv[0], "n", 1) == 0) { area->newmetric = 0; area->oldmetric = 1; } } 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; int ret; area = vty->index; assert (area); ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; /* Default is narrow metric. */ area->newmetric = 0; area->oldmetric = 1; 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; area = vty->index; assert (area); area->overload_bit = LSPBIT_OL; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); 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; area = vty->index; assert (area); area->overload_bit = 0; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } DEFUN (dynamic_hostname, dynamic_hostname_cmd, "hostname dynamic", "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") { struct isis_area *area; area = vty->index; assert (area); if (!area->dynhostname) { area->dynhostname = 1; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); } 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; area = vty->index; assert (area); if (area->dynhostname) { area->dynhostname = 0; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); } return CMD_SUCCESS; } 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 set_lsp_max_lifetime (struct vty *vty, struct isis_area *area, uint16_t interval, int level) { int lvl; int set_refresh_interval[ISIS_LEVELS] = {0, 0}; uint16_t refresh_interval; refresh_interval = interval - 300; 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; area->max_lsp_lifetime[lvl-1] = interval; /* Automatically reducing lsp_refresh_interval to interval - 300 */ if (set_refresh_interval[lvl-1]) area->lsp_refresh[lvl-1] = refresh_interval; } lsp_regenerate_schedule (area, level, 1); 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") { 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_max_lifetime (vty, area, interval, level); } DEFUN (no_max_lsp_lifetime, no_max_lsp_lifetime_cmd, "no max-lsp-lifetime", NO_STR "LSP lifetime in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_LSP_LIFETIME; level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1; return set_lsp_max_lifetime (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_LSP_LIFETIME; level = IS_LEVEL_1; return set_lsp_max_lifetime (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_LSP_LIFETIME; level = IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } 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 set_lsp_refresh_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_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; area->lsp_refresh[lvl-1] = interval; } lsp_regenerate_schedule (area, level, 1); 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") { 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_refresh_interval (vty, area, interval, level); } DEFUN (no_lsp_refresh_interval, no_lsp_refresh_interval_cmd, "no lsp-refresh-interval", NO_STR "LSP refresh interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MAX_LSP_GEN_INTERVAL; level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1; return set_lsp_refresh_interval (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MAX_LSP_GEN_INTERVAL; level = IS_LEVEL_1; return set_lsp_refresh_interval (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } 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") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MAX_LSP_GEN_INTERVAL; level = IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } 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") 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++; } /* 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++; } } /* 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 */ } } 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_isis_summary_cmd); install_element (ENABLE_NODE, &show_isis_interface_cmd); install_element (ENABLE_NODE, &show_isis_interface_detail_cmd); install_element (ENABLE_NODE, &show_isis_interface_arg_cmd); install_element (ENABLE_NODE, &show_isis_neighbor_cmd); install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd); install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd); install_element (ENABLE_NODE, &clear_isis_neighbor_cmd); install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd); install_element (ENABLE_NODE, &show_hostname_cmd); install_element (ENABLE_NODE, &show_database_cmd); install_element (ENABLE_NODE, &show_database_arg_cmd); install_element (ENABLE_NODE, &show_database_arg_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_arg_cmd); install_element (ENABLE_NODE, &show_debugging_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 (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, &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, &is_type_cmd); install_element (ISIS_NODE, &no_is_type_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); install_element (ISIS_NODE, &domain_passwd_md5_cmd); install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd); install_element (ISIS_NODE, &domain_passwd_clear_cmd); install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_domain_passwd_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, &set_overload_bit_cmd); install_element (ISIS_NODE, &no_set_overload_bit_cmd); install_element (ISIS_NODE, &dynamic_hostname_cmd); install_element (ISIS_NODE, &no_dynamic_hostname_cmd); install_element (ISIS_NODE, &metric_style_cmd); install_element (ISIS_NODE, &no_metric_style_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); install_element (ENABLE_NODE, &show_isis_generated_topology_cmd); #endif /* TOPOLOGY_GENERATE */ } quagga-0.99.22.4/isisd/isisd.conf.sample0000644000175000017500000000142512000052240014565 00000000000000! -*- 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-0.99.22.4/isisd/isisd.h0000644000175000017500000001241212177450262012632 00000000000000/* * 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" /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ /* #define EXTREME_TLV_DEBUG */ struct rmap { char *name; struct route_map *map; }; 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 */ /* Redistributed external information. */ struct route_table *external_info[ZEBRA_ROUTE_MAX + 1]; /* Redistribute metric info. */ struct { int type; /* Internal or External */ int value; /* metric value */ } dmetric[ZEBRA_ROUTE_MAX + 1]; struct { char *name; struct route_map *map; } rmap[ZEBRA_ROUTE_MAX + 1]; #ifdef HAVE_IPV6 struct { struct { char *name; struct route_map *map; } rmap[ZEBRA_ROUTE_MAX + 1]; } inet6_afmode; #endif }; 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 unsigned int min_bcast_mtu; struct list *circuit_list; /* IS-IS circuits */ struct flags flags; struct thread *t_tick; /* LSP walker */ struct thread *t_lsp_refresh[ISIS_LEVELS]; 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; 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; #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); /* 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) #endif /* ISISD_H */ quagga-0.99.22.4/isisd/iso_checksum.c0000644000175000017500000000370512000052240014146 00000000000000/* * 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-0.99.22.4/isisd/iso_checksum.h0000644000175000017500000000222412000052240014146 00000000000000/* * 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-0.99.22.4/isisd/topology/0000755000175000017500000000000012211704577013302 500000000000000quagga-0.99.22.4/isisd/topology/Makefile.am0000644000175000017500000000101212177450262015250 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -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 depend: @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c ## File dependency. quagga-0.99.22.4/isisd/topology/Makefile.in0000644000175000017500000004121412211704501015254 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(top_srcdir)/depcomp 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru libtopology_a_AR = $(AR) $(ARFLAGS) am_libtopology_a_OBJECTS = spgrid.$(OBJEXT) random.$(OBJEXT) libtopology_a_OBJECTS = $(am_libtopology_a_OBJECTS) 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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_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 .PRECIOUS: 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) -rm -f libtopology.a $(libtopology_a_AR) libtopology.a $(libtopology_a_OBJECTS) $(libtopology_a_LIBADD) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist ctags 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 uninstall uninstall-am depend: @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.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-0.99.22.4/isisd/topology/random.c0000644000175000017500000001277112000052240014631 00000000000000/*********************************************************************/ /* */ /* current processor time in seconds */ /* difference between two calls is processor time spent by your code */ /* needs: , */ /* depends on compiler and OS */ /* */ /*********************************************************************/ #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-0.99.22.4/isisd/topology/spgrid.c0000644000175000017500000004446312132522417014662 00000000000000#include #include #include #include "random.c" #include #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, y1, y2, yp, dl, dx, xn, yn, 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 -- ) { y1 = nrand ( Y ); do y2 = nrand ( Y ); while ( y2 == y1 ); i = NODE ( x, y1 ); j = NODE ( x, y2 ); 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 ) { yp = nrand(Y-y); yn = mess[ yp ]; mess[ yp ] = mess[ Y - y - 1 ]; } else yn = y; j = NODE ( xn, yn ); 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-0.99.22.4/isisd/topology/spgrid.h0000644000175000017500000000250012000052240014633 00000000000000/* * 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-0.99.22.4/lib/0000755000175000017500000000000012211704576011060 500000000000000quagga-0.99.22.4/lib/Makefile.am0000644000175000017500000000432312211105060013015 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" lib_LTLIBRARIES = libzebra.la libzebra_la_LDFLAGS = -version-info 0: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 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 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-0.99.22.4/lib/Makefile.in0000644000175000017500000006265512211704501013047 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(pkginclude_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/version.h.in \ $(top_srcdir)/depcomp 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) 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 libzebra_la_OBJECTS = $(am_libzebra_la_OBJECTS) libzebra_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libzebra_la_LDFLAGS) $(LDFLAGS) -o $@ 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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 = $(pkginclude_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ lib_LTLIBRARIES = libzebra.la libzebra_la_LDFLAGS = -version-info 0: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 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 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 .PRECIOUS: 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) $(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)/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)/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)/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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist ctags 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 uninstall uninstall-am \ uninstall-libLTLIBRARIES uninstall-pkgincludeHEADERS 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-0.99.22.4/lib/agentx.c0000644000175000017500000001404512177450262012437 00000000000000/* 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 "command.h" #include "smux.h" int agentx_enabled = 0; /* 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"); 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) { 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); return 1; } #endif /* HAVE_SNMP */ quagga-0.99.22.4/lib/buffer.c0000644000175000017500000002754712177450262012435 00000000000000/* * 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__, b->head, b->tail, 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-0.99.22.4/lib/buffer.h0000644000175000017500000001002212132522417012407 00000000000000/* * 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-0.99.22.4/lib/checksum.c0000644000175000017500000000601512177450262012751 00000000000000/* * 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-0.99.22.4/lib/checksum.h0000644000175000017500000000024312177450262012753 00000000000000extern 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-0.99.22.4/lib/command.c0000644000175000017500000025047612177450262012601 00000000000000/* Command interpreter routine for virtual terminal [aka TeletYpe] Copyright (C) 1997, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "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 desc desc_cr; char *command_cr = NULL; /* 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); } /* 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; } /* Install top node of command vector. */ void install_node (struct cmd_node *node, int (*func) (struct vty *)) { vector_set_index (cmdvec, node->node, node); node->func = func; node->cmd_vector = vector_init (VECTOR_MIN_SIZE); } /* Compare two command's string. Used in sort_node (). */ static int cmp_node (const void *p, const void *q) { const struct cmd_element *a = *(struct cmd_element * const *)p; const struct cmd_element *b = *(struct cmd_element * const *)q; return strcmp (a->string, b->string); } static int cmp_desc (const void *p, const void *q) { const struct desc *a = *(struct desc * const *)p; const struct desc *b = *(struct desc * const *)q; return strcmp (a->cmd, b->cmd); } /* Sort each node's command element according to command string. */ void sort_node () { unsigned int i, j; struct cmd_node *cnode; vector descvec; struct cmd_element *cmd_element; for (i = 0; i < vector_active (cmdvec); i++) if ((cnode = vector_slot (cmdvec, i)) != NULL) { vector cmd_vector = cnode->cmd_vector; qsort (cmd_vector->index, vector_active (cmd_vector), sizeof (void *), cmp_node); for (j = 0; j < vector_active (cmd_vector); j++) if ((cmd_element = vector_slot (cmd_vector, j)) != NULL && vector_active (cmd_element->strvec)) { descvec = vector_slot (cmd_element->strvec, vector_active (cmd_element->strvec) - 1); qsort (descvec->index, vector_active (descvec), sizeof (void *), cmp_desc); } } } /* Breaking up string into each command piece. I assume given character is separated by a space character. Return value is a vector which includes char ** data element. */ vector cmd_make_strvec (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); } /* Fetch next description. Used in cmd_make_descvec(). */ static char * cmd_desc_str (const char **string) { const char *cp, *start; char *token; int strlen; cp = *string; if (cp == NULL) return NULL; /* Skip white spaces. */ while (isspace ((int) *cp) && *cp != '\0') cp++; /* Return if there is only white spaces */ if (*cp == '\0') return NULL; start = cp; while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') cp++; strlen = cp - start; token = XMALLOC (MTYPE_STRVEC, strlen + 1); memcpy (token, start, strlen); *(token + strlen) = '\0'; *string = cp; return token; } /* New string vector. */ static vector cmd_make_descvec (const char *string, const char *descstr) { int multiple = 0; const char *sp; char *token; int len; const char *cp; const char *dp; vector allvec; vector strvec = NULL; struct desc *desc; cp = string; dp = descstr; if (cp == NULL) return NULL; allvec = vector_init (VECTOR_MIN_SIZE); while (1) { while (isspace ((int) *cp) && *cp != '\0') cp++; if (*cp == '(') { multiple = 1; cp++; } if (*cp == ')') { multiple = 0; cp++; } if (*cp == '|') { if (! multiple) { fprintf (stderr, "Command parse error!: %s\n", string); exit (1); } cp++; } while (isspace ((int) *cp) && *cp != '\0') cp++; if (*cp == '(') { multiple = 1; cp++; } if (*cp == '\0') return allvec; sp = cp; while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0') cp++; len = cp - sp; token = XMALLOC (MTYPE_STRVEC, len + 1); memcpy (token, sp, len); *(token + len) = '\0'; desc = XCALLOC (MTYPE_DESC, sizeof (struct desc)); desc->cmd = token; desc->str = cmd_desc_str (&dp); if (multiple) { if (multiple == 1) { strvec = vector_init (VECTOR_MIN_SIZE); vector_set (allvec, strvec); } multiple++; } else { strvec = vector_init (VECTOR_MIN_SIZE); vector_set (allvec, strvec); } vector_set (strvec, desc); } } /* Count mandantory string vector size. This is to determine inputed command has enough command length. */ static int cmd_cmdsize (vector strvec) { unsigned int i; int size = 0; vector descvec; struct desc *desc; for (i = 0; i < vector_active (strvec); i++) if ((descvec = vector_slot (strvec, i)) != NULL) { if ((vector_active (descvec)) == 1 && (desc = vector_slot (descvec, 0)) != NULL) { if (desc->cmd == NULL || CMD_OPTION (desc->cmd)) return size; else size++; } else size++; } return size; } /* 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) return; cnode = vector_slot (cmdvec, ntype); if (cnode == NULL) { fprintf (stderr, "Command node %d doesn't exist, please check it\n", ntype); exit (1); } vector_set (cnode->cmd_vector, cmd); if (cmd->strvec == NULL) cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc); cmd->cmdsize = cmd_cmdsize (cmd->strvec); } 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; } #if 0 /* Filter command vector by symbol. This function is not actually used; * should it be deleted? */ static int cmd_filter_by_symbol (char *command, char *symbol) { int i, lim; if (strcmp (symbol, "IPV4_ADDRESS") == 0) { i = 0; lim = strlen (command); while (i < lim) { if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/')) return 1; i++; } return 0; } if (strcmp (symbol, "STRING") == 0) { i = 0; lim = strlen (command); while (i < lim) { if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-')) return 1; i++; } return 0; } if (strcmp (symbol, "IFNAME") == 0) { i = 0; lim = strlen (command); while (i < lim) { if (! isalnum ((int) command[i])) return 1; i++; } return 0; } return 0; } #endif /* 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) { int state = STATE_START; int colons = 0, nums = 0, double_colon = 0; const char *sp = NULL; 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; /* I don't know why mask < 13 makes command match partly. Forgive me to make this comments. I Want to set static default route because of lack of function to originate default in ospf6d; sorry yasu if (mask < 13) return partly_match; */ return exact_match; } #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; } /* Make completion match and return match type flag. */ static enum match_type cmd_filter_by_completion (char *command, vector v, unsigned int index) { unsigned int i; const char *str; struct cmd_element *cmd_element; enum match_type match_type; vector descvec; struct desc *desc; match_type = no_match; /* If command and cmd_element string does not match set NULL to vector */ for (i = 0; i < vector_active (v); i++) if ((cmd_element = vector_slot (v, i)) != NULL) { if (index >= vector_active (cmd_element->strvec)) vector_slot (v, i) = NULL; else { unsigned int j; int matched = 0; descvec = vector_slot (cmd_element->strvec, index); for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) { str = desc->cmd; if (CMD_VARARG (str)) { if (match_type < vararg_match) match_type = vararg_match; matched++; } else if (CMD_RANGE (str)) { if (cmd_range_match (str, command)) { if (match_type < range_match) match_type = range_match; matched++; } } #ifdef HAVE_IPV6 else if (CMD_IPV6 (str)) { if (cmd_ipv6_match (command)) { if (match_type < ipv6_match) match_type = ipv6_match; matched++; } } else if (CMD_IPV6_PREFIX (str)) { if (cmd_ipv6_prefix_match (command)) { if (match_type < ipv6_prefix_match) match_type = ipv6_prefix_match; matched++; } } #endif /* HAVE_IPV6 */ else if (CMD_IPV4 (str)) { if (cmd_ipv4_match (command)) { if (match_type < ipv4_match) match_type = ipv4_match; matched++; } } else if (CMD_IPV4_PREFIX (str)) { if (cmd_ipv4_prefix_match (command)) { if (match_type < ipv4_prefix_match) match_type = ipv4_prefix_match; matched++; } } else /* Check is this point's argument optional ? */ if (CMD_OPTION (str) || CMD_VARIABLE (str)) { if (match_type < extend_match) match_type = extend_match; matched++; } else if (strncmp (command, str, strlen (command)) == 0) { if (strcmp (command, str) == 0) match_type = exact_match; else { if (match_type < partly_match) match_type = partly_match; } matched++; } } if (!matched) vector_slot (v, i) = NULL; } } return match_type; } /* Filter vector by command character with index. */ static enum match_type cmd_filter_by_string (char *command, vector v, unsigned int index) { unsigned int i; const char *str; struct cmd_element *cmd_element; enum match_type match_type; vector descvec; struct desc *desc; match_type = no_match; /* If command and cmd_element string does not match set NULL to vector */ for (i = 0; i < vector_active (v); i++) if ((cmd_element = vector_slot (v, i)) != NULL) { /* If given index is bigger than max string vector of command, set NULL */ if (index >= vector_active (cmd_element->strvec)) vector_slot (v, i) = NULL; else { unsigned int j; int matched = 0; descvec = vector_slot (cmd_element->strvec, index); for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) { str = desc->cmd; if (CMD_VARARG (str)) { if (match_type < vararg_match) match_type = vararg_match; matched++; } else if (CMD_RANGE (str)) { if (cmd_range_match (str, command)) { if (match_type < range_match) match_type = range_match; matched++; } } #ifdef HAVE_IPV6 else if (CMD_IPV6 (str)) { if (cmd_ipv6_match (command) == exact_match) { if (match_type < ipv6_match) match_type = ipv6_match; matched++; } } else if (CMD_IPV6_PREFIX (str)) { if (cmd_ipv6_prefix_match (command) == exact_match) { if (match_type < ipv6_prefix_match) match_type = ipv6_prefix_match; matched++; } } #endif /* HAVE_IPV6 */ else if (CMD_IPV4 (str)) { if (cmd_ipv4_match (command) == exact_match) { if (match_type < ipv4_match) match_type = ipv4_match; matched++; } } else if (CMD_IPV4_PREFIX (str)) { if (cmd_ipv4_prefix_match (command) == exact_match) { if (match_type < ipv4_prefix_match) match_type = ipv4_prefix_match; matched++; } } else if (CMD_OPTION (str) || CMD_VARIABLE (str)) { if (match_type < extend_match) match_type = extend_match; matched++; } else { if (strcmp (command, str) == 0) { match_type = exact_match; matched++; } } } if (!matched) vector_slot (v, i) = NULL; } } return match_type; } /* Check ambiguous match */ static int is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) { unsigned int i; unsigned int j; const char *str = NULL; struct cmd_element *cmd_element; const char *matched = NULL; vector descvec; struct desc *desc; for (i = 0; i < vector_active (v); i++) if ((cmd_element = vector_slot (v, i)) != NULL) { int match = 0; descvec = vector_slot (cmd_element->strvec, index); for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) { enum match_type ret; str = desc->cmd; switch (type) { case exact_match: if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) && strcmp (command, str) == 0) match++; break; case partly_match: if (!(CMD_OPTION (str) || CMD_VARIABLE (str)) && strncmp (command, str, strlen (command)) == 0) { if (matched && strcmp (matched, str) != 0) return 1; /* There is ambiguous match. */ else matched = str; match++; } break; case range_match: if (cmd_range_match (str, command)) { if (matched && strcmp (matched, str) != 0) return 1; else matched = str; match++; } break; #ifdef HAVE_IPV6 case ipv6_match: if (CMD_IPV6 (str)) match++; break; case ipv6_prefix_match: if ((ret = cmd_ipv6_prefix_match (command)) != no_match) { if (ret == partly_match) return 2; /* There is incomplete match. */ match++; } break; #endif /* HAVE_IPV6 */ case ipv4_match: if (CMD_IPV4 (str)) match++; break; case ipv4_prefix_match: if ((ret = cmd_ipv4_prefix_match (command)) != no_match) { if (ret == partly_match) return 2; /* There is incomplete match. */ match++; } break; case extend_match: if (CMD_OPTION (str) || CMD_VARIABLE (str)) match++; break; case no_match: default: break; } } if (!match) vector_slot (v, i) = NULL; } return 0; } /* If src matches dst return dst string, otherwise return NULL */ static const char * cmd_entry_function (const char *src, const char *dst) { /* Skip variable arguments. */ if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) || CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst)) return NULL; /* In case of 'command \t', given src is NULL string. */ if (src == NULL) return dst; /* Matched with input string. */ if (strncmp (src, dst, strlen (src)) == 0) return dst; return NULL; } /* If src matches dst return dst string, otherwise return NULL */ /* This version will return the dst string always if it is CMD_VARIABLE for '?' key processing */ static const char * cmd_entry_function_desc (const char *src, const char *dst) { if (CMD_VARARG (dst)) return dst; if (CMD_RANGE (dst)) { if (cmd_range_match (dst, src)) return dst; else return NULL; } #ifdef HAVE_IPV6 if (CMD_IPV6 (dst)) { if (cmd_ipv6_match (src)) return dst; else return NULL; } if (CMD_IPV6_PREFIX (dst)) { if (cmd_ipv6_prefix_match (src)) return dst; else return NULL; } #endif /* HAVE_IPV6 */ if (CMD_IPV4 (dst)) { if (cmd_ipv4_match (src)) return dst; else return NULL; } if (CMD_IPV4_PREFIX (dst)) { if (cmd_ipv4_prefix_match (src)) return dst; else return NULL; } /* Optional or variable commands always match on '?' */ if (CMD_OPTION (dst) || CMD_VARIABLE (dst)) return dst; /* In case of 'command \t', given src is NULL string. */ if (src == NULL) return dst; if (strncmp (src, dst, strlen (src)) == 0) return dst; else return NULL; } /* Check same string element existence. If it isn't there return 1. */ 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; } /* Compare string to description vector. If there is same string return 1 else return 0. */ static int desc_unique_string (vector v, const char *str) { unsigned int i; struct desc *desc; for (i = 0; i < vector_active (v); i++) if ((desc = vector_slot (v, i)) != NULL) if (strcmp (desc->cmd, str) == 0) return 1; return 0; } 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; } /* '?' 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; /* Set index. */ if (vector_active (vline) == 0) { *status = CMD_ERR_NO_MATCH; return NULL; } else 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. */ /* Only words precedes current word will be checked in this loop. */ for (i = 0; i < index; i++) if ((command = vector_slot (vline, i))) { match = cmd_filter_by_completion (command, cmd_vector, i); if (match == vararg_match) { struct cmd_element *cmd_element; vector descvec; unsigned int j, k; for (j = 0; j < vector_active (cmd_vector); j++) if ((cmd_element = vector_slot (cmd_vector, j)) != NULL && (vector_active (cmd_element->strvec))) { descvec = vector_slot (cmd_element->strvec, vector_active (cmd_element->strvec) - 1); for (k = 0; k < vector_active (descvec); k++) { struct desc *desc = vector_slot (descvec, k); vector_set (matchvec, desc); } } vector_set (matchvec, &desc_cr); vector_free (cmd_vector); return matchvec; } if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) { vector_free (cmd_vector); vector_free (matchvec); *status = CMD_ERR_AMBIGUOUS; return NULL; } else if (ret == 2) { vector_free (cmd_vector); vector_free (matchvec); *status = CMD_ERR_NO_MATCH; return NULL; } } /* Prepare match vector */ /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ /* Make sure that cmd_vector is filtered based on current word */ command = vector_slot (vline, index); if (command) match = cmd_filter_by_completion (command, cmd_vector, index); /* Make description vector. */ for (i = 0; i < vector_active (cmd_vector); i++) if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) { vector strvec = cmd_element->strvec; /* if command is NULL, index may be equal to vector_active */ if (command && index >= vector_active (strvec)) vector_slot (cmd_vector, i) = NULL; else { /* Check if command is completed. */ if (command == NULL && index == vector_active (strvec)) { if (!desc_unique_string (matchvec, command_cr)) vector_set (matchvec, &desc_cr); } else { unsigned int j; vector descvec = vector_slot (strvec, index); struct desc *desc; for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) { const char *string; string = cmd_entry_function_desc (command, desc->cmd); if (string) { /* Uniqueness check */ if (!desc_unique_string (matchvec, string)) vector_set (matchvec, desc); } } } } } vector_free (cmd_vector); if (vector_slot (matchvec, 0) == NULL) { vector_free (matchvec); *status = CMD_ERR_NO_MATCH; return NULL; } *status = CMD_SUCCESS; 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; } /* Command line completion support. */ static char ** cmd_complete_command_real (vector vline, struct vty *vty, int *status) { unsigned int i; vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); #define INIT_MATCHVEC_SIZE 10 vector matchvec; struct cmd_element *cmd_element; unsigned int index; char **match_str; struct desc *desc; vector descvec; char *command; int lcd; 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 preceeding command string */ for (i = 0; i < index; i++) if ((command = vector_slot (vline, i))) { enum match_type match; int ret; /* First try completion match, if there is exactly match return 1 */ match = cmd_filter_by_completion (command, cmd_vector, i); /* If there is exact match then filter ambiguous match else check ambiguousness. */ if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) { vector_free (cmd_vector); *status = CMD_ERR_AMBIGUOUS; return NULL; } /* else if (ret == 2) { vector_free (cmd_vector); *status = CMD_ERR_NO_MATCH; return NULL; } */ } /* Prepare match vector. */ matchvec = vector_init (INIT_MATCHVEC_SIZE); /* Now we got into completion */ for (i = 0; i < vector_active (cmd_vector); i++) if ((cmd_element = vector_slot (cmd_vector, i))) { const char *string; vector strvec = cmd_element->strvec; /* Check field length */ if (index >= vector_active (strvec)) vector_slot (cmd_vector, i) = NULL; else { unsigned int j; descvec = vector_slot (strvec, index); for (j = 0; j < vector_active (descvec); j++) if ((desc = vector_slot (descvec, j))) { if ((string = cmd_entry_function (vector_slot (vline, index), desc->cmd))) if (cmd_unique_string (matchvec, string)) vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); } } } /* We don't need cmd_vector any more. */ vector_free (cmd_vector); /* No matched command */ if (vector_slot (matchvec, 0) == NULL) { vector_free (matchvec); /* In case of 'command \t' pattern. Do you need '?' command at the end of the line. */ if (vector_slot (vline, index) == '\0') *status = CMD_ERR_NOTHING_TODO; else *status = CMD_ERR_NO_MATCH; return NULL; } /* Only one matched */ if (vector_slot (matchvec, 1) == NULL) { match_str = (char **) matchvec->index; vector_only_wrapper_free (matchvec); *status = CMD_COMPLETE_FULL_MATCH; return match_str; } /* Make it sure last element is NULL. */ vector_set (matchvec, NULL); /* Check LCD of matched strings. */ if (vector_slot (vline, index) != NULL) { lcd = cmd_lcd ((char **) matchvec->index); if (lcd) { int len = strlen (vector_slot (vline, index)); if (len < lcd) { char *lcdstr; lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1); memcpy (lcdstr, matchvec->index[0], lcd); lcdstr[lcd] = '\0'; /* match_str = (char **) &lcdstr; */ /* Free matchvec. */ for (i = 0; i < vector_active (matchvec); i++) { if (vector_slot (matchvec, i)) XFREE (MTYPE_STRVEC, vector_slot (matchvec, i)); } vector_free (matchvec); /* Make new matchvec. */ matchvec = vector_init (INIT_MATCHVEC_SIZE); vector_set (matchvec, lcdstr); match_str = (char **) matchvec->index; vector_only_wrapper_free (matchvec); *status = CMD_COMPLETE_MATCH; return match_str; } } } match_str = (char **) matchvec->index; vector_only_wrapper_free (matchvec); *status = CMD_COMPLETE_LIST_MATCH; return match_str; } char ** cmd_complete_command (vector vline, struct vty *vty, int *status) { 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); vector_free(shifted_vline); vty->node = onode; return ret; } return cmd_complete_command_real (vline, vty, status); } /* 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_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; default: ret = CONFIG_NODE; } return ret; } /* Execute command by argument vline vector. */ static int cmd_execute_command_real (vector vline, 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; int varflag; char *command; /* Make copy of command elements. */ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); for (index = 0; index < vector_active (vline); index++) if ((command = vector_slot (vline, index))) { int ret; match = cmd_filter_by_completion (command, cmd_vector, index); if (match == vararg_match) break; ret = is_cmd_ambiguous (command, cmd_vector, index, match); if (ret == 1) { vector_free (cmd_vector); return CMD_ERR_AMBIGUOUS; } else if (ret == 2) { vector_free (cmd_vector); return CMD_ERR_NO_MATCH; } } /* Check matched count. */ matched_element = NULL; matched_count = 0; incomplete_count = 0; for (i = 0; i < vector_active (cmd_vector); i++) if ((cmd_element = vector_slot (cmd_vector, i))) { if (match == vararg_match || index >= cmd_element->cmdsize) { matched_element = cmd_element; #if 0 printf ("DEBUG: %s\n", cmd_element->string); #endif matched_count++; } else { incomplete_count++; } } /* Finish of using cmd_vector. */ vector_free (cmd_vector); /* To execute command, matched_count must be 1. */ if (matched_count == 0) { if (incomplete_count) return CMD_ERR_INCOMPLETE; else return CMD_ERR_NO_MATCH; } if (matched_count > 1) return CMD_ERR_AMBIGUOUS; /* Argument treatment */ varflag = 0; argc = 0; for (i = 0; i < vector_active (vline); i++) { if (varflag) argv[argc++] = vector_slot (vline, i); else { vector descvec = vector_slot (matched_element->strvec, i); if (vector_active (descvec) == 1) { struct desc *desc = vector_slot (descvec, 0); if (CMD_VARARG (desc->cmd)) varflag = 1; if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) argv[argc++] = vector_slot (vline, i); } else argv[argc++] = vector_slot (vline, i); } if (argc >= CMD_ARGC_MAX) return CMD_ERR_EXEED_ARGC_MAX; } /* For vtysh execution. */ if (cmd) *cmd = matched_element; if (matched_element->daemon) return CMD_SUCCESS_DAEMON; /* Execute matched command. */ return (*matched_element->func) (matched_element, vty, argc, argv); } 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, vty, cmd); vector_free(shifted_vline); vty->node = onode; return ret; } saved_ret = ret = cmd_execute_command_real (vline, 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, 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 command by argument readline. */ int cmd_execute_command_strict (vector vline, 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]; int varflag; enum match_type match = 0; char *command; /* Make copy of command element */ cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); for (index = 0; index < vector_active (vline); index++) if ((command = vector_slot (vline, index))) { int ret; match = cmd_filter_by_string (vector_slot (vline, index), cmd_vector, index); /* If command meets '.VARARG' then finish matching. */ if (match == vararg_match) break; ret = is_cmd_ambiguous (command, cmd_vector, index, match); if (ret == 1) { vector_free (cmd_vector); return CMD_ERR_AMBIGUOUS; } if (ret == 2) { vector_free (cmd_vector); return CMD_ERR_NO_MATCH; } } /* Check matched count. */ matched_element = NULL; matched_count = 0; incomplete_count = 0; for (i = 0; i < vector_active (cmd_vector); i++) if (vector_slot (cmd_vector, i) != NULL) { cmd_element = vector_slot (cmd_vector, i); if (match == vararg_match || index >= cmd_element->cmdsize) { matched_element = cmd_element; matched_count++; } else incomplete_count++; } /* Finish of using cmd_vector. */ vector_free (cmd_vector); /* To execute command, matched_count must be 1. */ if (matched_count == 0) { if (incomplete_count) return CMD_ERR_INCOMPLETE; else return CMD_ERR_NO_MATCH; } if (matched_count > 1) return CMD_ERR_AMBIGUOUS; /* Argument treatment */ varflag = 0; argc = 0; for (i = 0; i < vector_active (vline); i++) { if (varflag) argv[argc++] = vector_slot (vline, i); else { vector descvec = vector_slot (matched_element->strvec, i); if (vector_active (descvec) == 1) { struct desc *desc = vector_slot (descvec, 0); if (CMD_VARARG (desc->cmd)) varflag = 1; if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd)) argv[argc++] = vector_slot (vline, i); } else argv[argc++] = vector_slot (vline, i); } if (argc >= CMD_ARGC_MAX) return CMD_ERR_EXEED_ARGC_MAX; } /* For vtysh execution. */ if (cmd) *cmd = matched_element; if (matched_element->daemon) return CMD_SUCCESS_DAEMON; /* Now execute matched command */ return (*matched_element->func) (matched_element, vty, argc, argv); } /* Configration make from file. */ int config_from_file (struct vty *vty, FILE *fp) { int ret; vector vline; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { vline = cmd_make_strvec (vty->buf); /* In case of comment line */ if (vline == NULL) continue; /* Execute configuration command : this is strict match */ ret = cmd_execute_command_strict (vline, vty, NULL); /* Try again with setting node to CONFIG_NODE */ while (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, NULL); } cmd_free_strvec (vline); 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 VTY_NODE: vty->node = CONFIG_NODE; break; case BGP_VPNV4_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; 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_VPNV4_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 VTY_NODE: vty_config_unlock (vty); vty->node = ENABLE_NODE; break; default: break; } return CMD_SUCCESS; } /* Show version. */ DEFUN (show_version, show_version_cmd, "show version", SHOW_STR "Displays zebra version\n") { vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"", VTY_NEWLINE); vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, 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; 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->fd = fd; file_vty->type = VTY_FILE; /* Config file header print. */ vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! "); vty_time_print (file_vty, 1); vty_out (file_vty, "!\n"); for (i = 0; i < vector_active (cmdvec); i++) if ((node = vector_slot (cmdvec, i)) && node->func) { if ((*node->func) (file_vty)) vty_out (file_vty, "!\n"); } vty_close (file_vty); if (unlink (config_file_sav) != 0) if (errno != ENOENT) { vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav, VTY_NEWLINE); 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; } sync (); if (unlink (config_file) != 0) { vty_out (vty, "Can't unlink configuration file %s.%s", config_file, VTY_NEWLINE); goto finished; } if (link (config_file_tmp, config_file) != 0) { vty_out (vty, "Can't save configuration file %s.%s", config_file, VTY_NEWLINE); goto finished; } sync (); 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: 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; } /* 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); } void install_default (enum node_type node) { install_element (node, &config_exit_cmd); install_element (node, &config_quit_cmd); install_element (node, &config_end_cmd); install_element (node, &config_help_cmd); install_element (node, &config_list_cmd); install_element (node, &config_write_terminal_cmd); install_element (node, &config_write_file_cmd); install_element (node, &config_write_memory_cmd); install_element (node, &config_write_cmd); install_element (node, &show_running_config_cmd); } /* Initialize command interface. Install basic nodes and commands. */ void cmd_init (int terminal) { command_cr = XSTRDUP(MTYPE_STRVEC, ""); desc_cr.cmd = command_cr; desc_cr.str = XSTRDUP(MTYPE_STRVEC, ""); /* 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_element (VIEW_NODE, &config_list_cmd); install_element (VIEW_NODE, &config_exit_cmd); install_element (VIEW_NODE, &config_quit_cmd); install_element (VIEW_NODE, &config_help_cmd); install_element (VIEW_NODE, &config_enable_cmd); install_element (VIEW_NODE, &config_terminal_length_cmd); install_element (VIEW_NODE, &config_terminal_no_length_cmd); install_element (VIEW_NODE, &show_logging_cmd); install_element (VIEW_NODE, &echo_cmd); install_element (RESTRICTED_NODE, &config_list_cmd); install_element (RESTRICTED_NODE, &config_exit_cmd); install_element (RESTRICTED_NODE, &config_quit_cmd); install_element (RESTRICTED_NODE, &config_help_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, &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); install_element (ENABLE_NODE, &show_version_cmd); if (terminal) { install_element (ENABLE_NODE, &config_terminal_length_cmd); install_element (ENABLE_NODE, &config_terminal_no_length_cmd); install_element (ENABLE_NODE, &show_logging_cmd); install_element (ENABLE_NODE, &echo_cmd); 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 (ENABLE_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 (ENABLE_NODE, &show_work_queues_cmd); } srand(time(NULL)); } void cmd_terminate () { unsigned int i, j, k, l; struct cmd_node *cmd_node; struct cmd_element *cmd_element; struct desc *desc; vector cmd_node_v, cmd_element_v, desc_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_element->strvec != NULL) { cmd_element_v = cmd_element->strvec; for (k = 0; k < vector_active (cmd_element_v); k++) if ((desc_v = vector_slot (cmd_element_v, k)) != NULL) { for (l = 0; l < vector_active (desc_v); l++) if ((desc = vector_slot (desc_v, l)) != NULL) { if (desc->cmd) XFREE (MTYPE_STRVEC, desc->cmd); if (desc->str) XFREE (MTYPE_STRVEC, desc->str); XFREE (MTYPE_DESC, desc); } vector_free (desc_v); } cmd_element->strvec = NULL; vector_free (cmd_element_v); } vector_free (cmd_node_v); } vector_free (cmdvec); cmdvec = NULL; } if (command_cr) XFREE(MTYPE_STRVEC, command_cr); if (desc_cr.str) XFREE(MTYPE_STRVEC, desc_cr.str); 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-0.99.22.4/lib/command.h0000644000175000017500000003243012177450262012572 00000000000000/* * 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" /* 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. */ 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_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. */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ ISIS_NODE, /* ISIS 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. */ }; /* 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; }; 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 strvec; /* Pointing out each description vector. */ unsigned int cmdsize; /* Command index count. */ char *config; /* Configuration string */ vector subconfig; /* Sub configuration string */ u_char attr; /* Command attributes */ }; /* Command description structure. */ struct desc { char *cmd; /* Command string. */ char *str; /* Command's description. */ }; /* Return value of the commands. */ #define CMD_SUCCESS 0 #define CMD_WARNING 1 #define CMD_ERR_NO_MATCH 2 #define CMD_ERR_AMBIGUOUS 3 #define CMD_ERR_INCOMPLETE 4 #define CMD_ERR_EXEED_ARGC_MAX 5 #define CMD_ERR_NOTHING_TODO 6 #define CMD_COMPLETE_FULL_MATCH 7 #define CMD_COMPLETE_MATCH 8 #define CMD_COMPLETE_LIST_MATCH 9 #define CMD_SUCCESS_DAEMON 10 /* Argc max counts. */ #define CMD_ARGC_MAX 25 /* Turn off these macros when uisng cpp with extract.pl */ #ifndef VTYSH_EXTRACT_PL /* 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 ;-). */ #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 */ /* Some macroes */ #define CMD_OPTION(S) ((S[0]) == '[') #define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) #define CMD_VARARG(S) ((S[0]) == '.') #define CMD_RANGE(S) ((S[0] == '<')) #define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) #define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) #define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) #define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) /* Common descriptions. */ #define SHOW_STR "Show running system information\n" #define IP_STR "IP information\n" #define IPV6_STR "IPv6 information\n" #define NO_STR "Negate a command or set its defaults\n" #define 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 OSPF_STR "OSPF information\n" #define NEIGHBOR_STR "Specify neighbor router\n" #define DEBUG_STR "Debugging functions (see also 'undebug')\n" #define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" #define ROUTER_STR "Enable a routing process\n" #define AS_STR "AS number\n" #define MBGP_STR "MBGP information\n" #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" #define OUT_STR "Filter outgoing routing updates\n" #define IN_STR "Filter incoming routing updates\n" #define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n" #define OSPF6_NUMBER_STR "Specify by number\n" #define INTERFACE_STR "Interface infomation\n" #define IFNAME_STR "Interface name(e.g. ep0)\n" #define IP6_STR "IPv6 Information\n" #define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n" #define OSPF6_ROUTER_STR "Enable a routing process\n" #define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n" #define SECONDS_STR "<1-65535> Seconds\n" #define ROUTE_STR "Routing Table\n" #define PREFIX_LIST_STR "Build a prefix list\n" #define OSPF6_DUMP_TYPE_LIST \ "(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" #define ISIS_STR "IS-IS information\n" #define AREA_TAG_STR "[area tag]\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 *); extern void sort_node (void); /* 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 const char *cmd_prompt (enum node_type); extern int config_from_file (struct vty *, FILE *); 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 config_replace_string (struct cmd_element *, char *, ...); 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 char *host_config_file (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-0.99.22.4/lib/daemon.c0000644000175000017500000000333312132522417012403 00000000000000/* * 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-0.99.22.4/lib/distribute.c0000644000175000017500000005243012177450262013327 00000000000000/* 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) { if (dist->ifname) XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname); if (dist->list[DISTRIBUTE_IN]) free (dist->list[DISTRIBUTE_IN]); if (dist->list[DISTRIBUTE_OUT]) free (dist->list[DISTRIBUTE_OUT]); if (dist->prefix[DISTRIBUTE_IN]) free (dist->prefix[DISTRIBUTE_IN]); if (dist->prefix[DISTRIBUTE_OUT]) free (dist->prefix[DISTRIBUTE_OUT]); XFREE (MTYPE_DISTRIBUTE, dist); } /* Lookup interface's distribute list. */ struct distribute * distribute_lookup (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 (type == DISTRIBUTE_IN) { if (dist->list[DISTRIBUTE_IN]) free (dist->list[DISTRIBUTE_IN]); dist->list[DISTRIBUTE_IN] = strdup (alist_name); } if (type == DISTRIBUTE_OUT) { if (dist->list[DISTRIBUTE_OUT]) free (dist->list[DISTRIBUTE_OUT]); dist->list[DISTRIBUTE_OUT] = strdup (alist_name); } /* Apply this distribute-list to the interface. */ (*distribute_add_hook) (dist); return dist; } /* Unset distribute-list. If matched distribute-list exist then return 1. */ 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 (type == DISTRIBUTE_IN) { if (!dist->list[DISTRIBUTE_IN]) return 0; if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0) return 0; free (dist->list[DISTRIBUTE_IN]); dist->list[DISTRIBUTE_IN] = NULL; } if (type == DISTRIBUTE_OUT) { if (!dist->list[DISTRIBUTE_OUT]) return 0; if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0) return 0; free (dist->list[DISTRIBUTE_OUT]); dist->list[DISTRIBUTE_OUT] = NULL; } /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); /* If both out and in is NULL then free distribute list. */ if (dist->list[DISTRIBUTE_IN] == NULL && dist->list[DISTRIBUTE_OUT] == NULL && dist->prefix[DISTRIBUTE_IN] == NULL && dist->prefix[DISTRIBUTE_OUT] == NULL) { hash_release (disthash, dist); distribute_free (dist); } return 1; } /* Set access-list name to the distribute list. */ 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 (type == DISTRIBUTE_IN) { if (dist->prefix[DISTRIBUTE_IN]) free (dist->prefix[DISTRIBUTE_IN]); dist->prefix[DISTRIBUTE_IN] = strdup (plist_name); } if (type == DISTRIBUTE_OUT) { if (dist->prefix[DISTRIBUTE_OUT]) free (dist->prefix[DISTRIBUTE_OUT]); dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name); } /* Apply this distribute-list to the interface. */ (*distribute_add_hook) (dist); return dist; } /* Unset distribute-list. If matched distribute-list exist then return 1. */ 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 (type == DISTRIBUTE_IN) { if (!dist->prefix[DISTRIBUTE_IN]) return 0; if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0) return 0; free (dist->prefix[DISTRIBUTE_IN]); dist->prefix[DISTRIBUTE_IN] = NULL; } if (type == DISTRIBUTE_OUT) { if (!dist->prefix[DISTRIBUTE_OUT]) return 0; if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0) return 0; free (dist->prefix[DISTRIBUTE_OUT]); dist->prefix[DISTRIBUTE_OUT] = NULL; } /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); /* If both out and in is NULL then free distribute list. */ if (dist->list[DISTRIBUTE_IN] == NULL && dist->list[DISTRIBUTE_OUT] == NULL && dist->prefix[DISTRIBUTE_IN] == NULL && dist->prefix[DISTRIBUTE_OUT] == NULL) { hash_release (disthash, dist); distribute_free (dist); } return 1; } DEFUN (distribute_list_all, distribute_list_all_cmd, "distribute-list WORD (in|out)", "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n") { enum distribute_type type; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_set (NULL, type, argv[0]); return CMD_SUCCESS; } ALIAS (distribute_list_all, ipv6_distribute_list_all_cmd, "distribute-list WORD (in|out)", "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n") DEFUN (no_distribute_list_all, no_distribute_list_all_cmd, "no distribute-list WORD (in|out)", NO_STR "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n") { int ret; enum distribute_type type; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } ret = distribute_list_unset (NULL, type, argv[0]); if (! ret) { vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_distribute_list_all, no_ipv6_distribute_list_all_cmd, "no distribute-list WORD (in|out)", NO_STR "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n") DEFUN (distribute_list, distribute_list_cmd, "distribute-list WORD (in|out) WORD", "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" "Interface name\n") { enum distribute_type type; /* Check of distribute list type. */ if (strncmp (argv[1], "i", 1) == 0) type = DISTRIBUTE_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_set (argv[2], type, argv[0]); return CMD_SUCCESS; } ALIAS (distribute_list, ipv6_distribute_list_cmd, "distribute-list WORD (in|out) WORD", "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" "Interface name\n") DEFUN (no_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_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } ret = distribute_list_unset (argv[2], type, argv[0]); if (! ret) { vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_distribute_list, no_ipv6_distribute_list_cmd, "no distribute-list WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" "Interface name\n") DEFUN (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_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_prefix_set (NULL, type, argv[0]); return CMD_SUCCESS; } ALIAS (distribute_list_prefix_all, ipv6_distribute_list_prefix_all_cmd, "distribute-list prefix WORD (in|out)", "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" "Name of an IP prefix-list\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n") DEFUN (no_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_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } ret = distribute_list_prefix_unset (NULL, type, argv[0]); if (! ret) { vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_distribute_list_prefix_all, no_ipv6_distribute_list_prefix_all_cmd, "no distribute-list prefix WORD (in|out)", NO_STR "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" "Name of an IP prefix-list\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n") DEFUN (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_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } /* Get interface name corresponding distribute list. */ distribute_list_prefix_set (argv[2], type, argv[0]); return CMD_SUCCESS; } ALIAS (distribute_list_prefix, ipv6_distribute_list_prefix_cmd, "distribute-list prefix WORD (in|out) WORD", "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" "Name of an IP prefix-list\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" "Interface name\n") DEFUN (no_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_IN; else if (strncmp (argv[1], "o", 1) == 0) type = DISTRIBUTE_OUT; else { vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); return CMD_WARNING; } ret = distribute_list_prefix_unset (argv[2], type, argv[0]); if (! ret) { vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd, "no distribute-list prefix WORD (in|out) WORD", NO_STR "Filter networks in routing updates\n" "Filter prefixes in routing updates\n" "Name of an IP prefix-list\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" "Interface name\n") int config_show_distribute (struct vty *vty) { unsigned int i; struct hash_backet *mp; struct distribute *dist; /* Output filter configuration. */ dist = distribute_lookup (NULL); if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])) { vty_out (vty, " Outgoing update filter list for all interface is"); if (dist->list[DISTRIBUTE_OUT]) vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); if (dist->prefix[DISTRIBUTE_OUT]) vty_out (vty, "%s (prefix-list) %s", dist->list[DISTRIBUTE_OUT] ? "," : "", dist->prefix[DISTRIBUTE_OUT]); vty_out (vty, "%s", VTY_NEWLINE); } else vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE); for (i = 0; i < disthash->size; i++) for (mp = disthash->index[i]; mp; mp = mp->next) { dist = mp->data; if (dist->ifname) if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]) { vty_out (vty, " %s filtered by", dist->ifname); if (dist->list[DISTRIBUTE_OUT]) vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); if (dist->prefix[DISTRIBUTE_OUT]) vty_out (vty, "%s (prefix-list) %s", dist->list[DISTRIBUTE_OUT] ? "," : "", dist->prefix[DISTRIBUTE_OUT]); vty_out (vty, "%s", VTY_NEWLINE); } } /* Input filter configuration. */ dist = distribute_lookup (NULL); if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])) { vty_out (vty, " Incoming update filter list for all interface is"); if (dist->list[DISTRIBUTE_IN]) vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); if (dist->prefix[DISTRIBUTE_IN]) vty_out (vty, "%s (prefix-list) %s", dist->list[DISTRIBUTE_IN] ? "," : "", dist->prefix[DISTRIBUTE_IN]); vty_out (vty, "%s", VTY_NEWLINE); } else vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE); for (i = 0; i < disthash->size; i++) for (mp = disthash->index[i]; mp; mp = mp->next) { dist = mp->data; if (dist->ifname) if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]) { vty_out (vty, " %s filtered by", dist->ifname); if (dist->list[DISTRIBUTE_IN]) vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); if (dist->prefix[DISTRIBUTE_IN]) vty_out (vty, "%s (prefix-list) %s", dist->list[DISTRIBUTE_IN] ? "," : "", dist->prefix[DISTRIBUTE_IN]); vty_out (vty, "%s", VTY_NEWLINE); } } return 0; } /* Configuration write function. */ int config_write_distribute (struct vty *vty) { unsigned int i; struct hash_backet *mp; int write = 0; for (i = 0; i < disthash->size; i++) for (mp = disthash->index[i]; mp; mp = mp->next) { struct distribute *dist; dist = mp->data; if (dist->list[DISTRIBUTE_IN]) { vty_out (vty, " distribute-list %s in %s%s", dist->list[DISTRIBUTE_IN], dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; } if (dist->list[DISTRIBUTE_OUT]) { vty_out (vty, " distribute-list %s out %s%s", dist->list[DISTRIBUTE_OUT], dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; } if (dist->prefix[DISTRIBUTE_IN]) { vty_out (vty, " distribute-list prefix %s in %s%s", dist->prefix[DISTRIBUTE_IN], dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; } if (dist->prefix[DISTRIBUTE_OUT]) { vty_out (vty, " distribute-list prefix %s out %s%s", dist->prefix[DISTRIBUTE_OUT], dist->ifname ? dist->ifname : "", VTY_NEWLINE); write++; } } return write; } /* Clear all distribute list. */ void distribute_list_reset () { hash_clean (disthash, (void (*) (void *)) distribute_free); } /* Initialize distribute list related hash. */ void distribute_list_init (int node) { disthash = hash_create (distribute_hash_make, (int (*) (const void *, const void *)) distribute_cmp); if(node==RIP_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); } else if (node == RIPNG_NODE || node == BABEL_NODE) { /* WARNING: two identical commands installed do a crash, so be worry with aliases. For this reason, and because all these commands are aliases, Babel is not set with RIP. */ 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); } } quagga-0.99.22.4/lib/distribute.h0000644000175000017500000000353412177450262013335 00000000000000/* 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" /* Disctirubte list types. */ enum distribute_type { DISTRIBUTE_IN, DISTRIBUTE_OUT, DISTRIBUTE_MAX }; struct distribute { /* Name of the interface. */ char *ifname; /* Filter name of `in' and `out' */ char *list[DISTRIBUTE_MAX]; /* prefix-list name of `in' and `out' */ char *prefix[DISTRIBUTE_MAX]; }; /* Prototypes for distribute-list. */ 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-0.99.22.4/lib/filter.c0000644000175000017500000015340312132522417012431 00000000000000/* 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) (struct access_list *); /* Hook function which is executed when access_list is deleted. */ void (*delete_hook) (struct access_list *); }; /* 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 (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 (strcmp (access->name, name) == 0) return access; for (access = master->str.head; access; access = access->next) if (strcmp (access->name, name) == 0) return access; return NULL; } /* Get access list from list of access_list. If there isn't matched access_list create new one and return it. */ 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) (struct access_list *access)) { access_master_ipv4.add_hook = func; #ifdef HAVE_IPV6 access_master_ipv6.add_hook = func; #endif /* HAVE_IPV6 */ } /* Delete hook function. */ void access_list_delete_hook (void (*func) (struct access_list *access)) { access_master_ipv4.delete_hook = func; #ifdef HAVE_IPV6 access_master_ipv6.delete_hook = func; #endif /* HAVE_IPV6 */ } /* Add new filter to the end of specified access_list. */ 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); } /* 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; master = access->master; if (filter->next) filter->next->prev = filter->prev; else access->tail = filter->prev; if (filter->prev) filter->prev->next = filter->next; else access->head = filter->next; filter_free (filter); /* If access_list becomes empty delete it from access_master. */ if (access_list_empty (access)) access_list_delete (access); /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (access); } /* deny Specify packets to reject permit Specify packets to forward dynamic ? */ /* Hostname or A.B.C.D Address to match any Any source host host A single host address */ 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; /* 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; /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (access); /* Delete all filter from access-list. */ access_list_delete (access); return CMD_SUCCESS; } DEFUN (access_list_remark, access_list_remark_cmd, "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", "Add an access list entry\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list\n" "Access list entry comment\n" "Comment up to 100 characters\n") { struct access_list *access; 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; /* 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; /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (access); /* Delete all filter from access-list. */ access_list_delete (access); return CMD_SUCCESS; } DEFUN (ipv6_access_list_remark, ipv6_access_list_remark_cmd, "ipv6 access-list WORD remark .LINE", IPV6_STR "Add an access list entry\n" "IPv6 zebra access-list\n" "Access list entry comment\n" "Comment up to 100 characters\n") { struct access_list *access; 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 (name && strcmp (access->name, name) != 0) continue; write = 1; for (mfilter = access->head; mfilter; mfilter = mfilter->next) { filter = &mfilter->u.cfilter; if (write) { vty_out (vty, "%s IP%s access list %s%s", mfilter->cisco ? (filter->extended ? "Extended" : "Standard") : "Zebra", afi == AFI_IP6 ? "v6" : "", access->name, VTY_NEWLINE); write = 0; } vty_out (vty, " %s%s", filter_type_str (mfilter), mfilter->type == FILTER_DENY ? " " : ""); if (! mfilter->cisco) config_write_access_zebra (vty, mfilter); else if (filter->extended) config_write_access_cisco (vty, mfilter); else { if (filter->addr_mask.s_addr == 0xffffffff) vty_out (vty, " any%s", VTY_NEWLINE); else { vty_out (vty, " %s", inet_ntoa (filter->addr)); if (filter->addr_mask.s_addr != 0) vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask)); vty_out (vty, "%s", VTY_NEWLINE); } } } } for (access = master->str.head; access; access = access->next) { if (name && strcmp (access->name, name) != 0) continue; write = 1; for (mfilter = access->head; mfilter; mfilter = mfilter->next) { filter = &mfilter->u.cfilter; if (write) { vty_out (vty, "%s IP%s access list %s%s", mfilter->cisco ? (filter->extended ? "Extended" : "Standard") : "Zebra", afi == AFI_IP6 ? "v6" : "", access->name, VTY_NEWLINE); write = 0; } vty_out (vty, " %s%s", filter_type_str (mfilter), mfilter->type == FILTER_DENY ? " " : ""); if (! mfilter->cisco) config_write_access_zebra (vty, mfilter); else if (filter->extended) config_write_access_cisco (vty, mfilter); else { if (filter->addr_mask.s_addr == 0xffffffff) vty_out (vty, " any%s", VTY_NEWLINE); else { vty_out (vty, " %s", inet_ntoa (filter->addr)); if (filter->addr_mask.s_addr != 0) vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask)); vty_out (vty, "%s", VTY_NEWLINE); } } } } return CMD_SUCCESS; } DEFUN (show_ip_access_list, show_ip_access_list_cmd, "show ip access-list", SHOW_STR IP_STR "List IP access lists\n") { return filter_show (vty, NULL, AFI_IP); } DEFUN (show_ip_access_list_name, show_ip_access_list_name_cmd, "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", SHOW_STR IP_STR "List IP access lists\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list\n") { return filter_show (vty, argv[0], AFI_IP); } #ifdef HAVE_IPV6 DEFUN (show_ipv6_access_list, show_ipv6_access_list_cmd, "show ipv6 access-list", SHOW_STR IPV6_STR "List IPv6 access lists\n") { return filter_show (vty, NULL, AFI_IP6); } DEFUN (show_ipv6_access_list_name, show_ipv6_access_list_name_cmd, "show ipv6 access-list WORD", SHOW_STR IPV6_STR "List IPv6 access lists\n" "IPv6 zebra access-list\n") { return filter_show (vty, argv[0], AFI_IP6); } #endif /* HAVE_IPV6 */ void config_write_access_cisco (struct vty *vty, struct filter *mfilter) { struct filter_cisco *filter; filter = &mfilter->u.cfilter; if (filter->extended) { vty_out (vty, " ip"); if (filter->addr_mask.s_addr == 0xffffffff) vty_out (vty, " any"); else if (filter->addr_mask.s_addr == 0) vty_out (vty, " host %s", inet_ntoa (filter->addr)); else { vty_out (vty, " %s", inet_ntoa (filter->addr)); vty_out (vty, " %s", inet_ntoa (filter->addr_mask)); } if (filter->mask_mask.s_addr == 0xffffffff) vty_out (vty, " any"); else if (filter->mask_mask.s_addr == 0) vty_out (vty, " host %s", inet_ntoa (filter->mask)); else { vty_out (vty, " %s", inet_ntoa (filter->mask)); vty_out (vty, " %s", inet_ntoa (filter->mask_mask)); } vty_out (vty, "%s", VTY_NEWLINE); } else { if (filter->addr_mask.s_addr == 0xffffffff) vty_out (vty, " any%s", VTY_NEWLINE); else { vty_out (vty, " %s", inet_ntoa (filter->addr)); if (filter->addr_mask.s_addr != 0) vty_out (vty, " %s", inet_ntoa (filter->addr_mask)); vty_out (vty, "%s", VTY_NEWLINE); } } } void config_write_access_zebra (struct vty *vty, struct filter *mfilter) { struct filter_zebra *filter; struct prefix *p; char buf[BUFSIZ]; filter = &mfilter->u.zfilter; p = &filter->prefix; if (p->prefixlen == 0 && ! filter->exact) vty_out (vty, " any"); else vty_out (vty, " %s/%d%s", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, filter->exact ? " exact-match" : ""); vty_out (vty, "%s", VTY_NEWLINE); } 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-0.99.22.4/lib/filter.h0000644000175000017500000000334412132522417012434 00000000000000/* * Route filtering function. * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_FILTER_H #define _ZEBRA_FILTER_H #include "if.h" /* Filter type is made by `permit', `deny' and `dynamic'. */ enum filter_type { FILTER_DENY, FILTER_PERMIT, FILTER_DYNAMIC }; enum access_type { ACCESS_TYPE_STRING, ACCESS_TYPE_NUMBER }; /* Access list */ struct access_list { char *name; char *remark; struct access_master *master; enum access_type type; struct access_list *next; struct access_list *prev; struct filter *head; struct filter *tail; }; /* Prototypes for access-list. */ extern void access_list_init (void); extern void access_list_reset (void); extern void access_list_add_hook (void (*func)(struct access_list *)); extern void access_list_delete_hook (void (*func)(struct access_list *)); 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-0.99.22.4/lib/getopt.c0000644000175000017500000007312112132522417012444 00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #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-0.99.22.4/lib/getopt.h0000644000175000017500000001221512132522417012446 00000000000000/* 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-0.99.22.4/lib/getopt1.c0000644000175000017500000001073512132522417012527 00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #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-0.99.22.4/lib/gitversion.pl0000644000175000017500000000233012177450262013525 00000000000000#!/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; hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); hash->index = XCALLOC (MTYPE_HASH_INDEX, sizeof (struct hash_backet *) * size); hash->size = size; hash->hash_key = hash_key; hash->hash_cmp = hash_cmp; hash->count = 0; return hash; } /* Allocate a new hash with default hash size. */ struct hash * hash_create (unsigned int (*hash_key) (void *), int (*hash_cmp) (const void *, const void *)) { return hash_create_size (HASHTABSIZE, hash_key, hash_cmp); } /* Utility function for hash_get(). When this function is specified as alloc_func, return arugment as it is. This function is used for intern already allocated value. */ void * hash_alloc_intern (void *arg) { return arg; } /* Lookup and return hash backet in hash. If there is no corresponding hash backet and alloc_func is specified, create new hash backet. */ void * hash_get (struct hash *hash, void *data, void * (*alloc_func) (void *)) { unsigned int key; unsigned int index; void *newdata; struct hash_backet *backet; key = (*hash->hash_key) (data); index = key % hash->size; for (backet = hash->index[index]; backet != NULL; backet = backet->next) if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) return backet->data; if (alloc_func) { newdata = (*alloc_func) (data); if (newdata == NULL) return NULL; backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); backet->data = newdata; backet->key = key; backet->next = hash->index[index]; hash->index[index] = backet; hash->count++; return backet->data; } return NULL; } /* Hash lookup. */ void * hash_lookup (struct hash *hash, void *data) { return hash_get (hash, data, NULL); } /* 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; 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-0.99.22.4/lib/hash.h0000644000175000017500000000405212211704467012074 00000000000000/* Hash routine. Copyright (C) 1998 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_HASH_H #define _ZEBRA_HASH_H /* Default hash table size. */ #define HASHTABSIZE 1024 struct hash_backet { /* Linked list. */ struct hash_backet *next; /* Hash key. */ unsigned int key; /* Data. */ void *data; }; struct hash { /* Hash backet. */ struct hash_backet **index; /* Hash table size. */ unsigned int size; /* Key make function. */ unsigned int (*hash_key) (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-0.99.22.4/lib/if.c0000644000175000017500000005022712177450262011551 00000000000000 /* * Interface functions. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "vector.h" #include "vty.h" #include "command.h" #include "if.h" #include "sockunion.h" #include "prefix.h" #include "memory.h" #include "table.h" #include "buffer.h" #include "str.h" #include "log.h" /* Master list of interfaces. */ struct list *iflist; /* One for each program. This structure is needed to store hooks. */ struct if_master { int (*if_new_hook) (struct interface *); int (*if_delete_hook) (struct interface *); } if_master; /* 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 (const char *name, int namelen) { struct interface *ifp; 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'; if (if_lookup_by_name(ifp->name) == NULL) listnode_add_sort (iflist, ifp); else zlog_err("if_create(%s): corruption detected -- interface with this " "name exists already!", ifp->name); ifp->connected = list_new (); ifp->connected->del = (void (*) (void *)) connected_free; if (if_master.if_new_hook) (*if_master.if_new_hook) (ifp); return ifp; } /* Delete 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 (iflist, ifp); if_delete_retain(ifp); list_free (ifp->connected); XFREE (MTYPE_IF, ifp); } /* Add hook to interface master. */ void if_add_hook (int type, int (*func)(struct interface *ifp)) { switch (type) { case IF_NEW_HOOK: if_master.if_new_hook = func; break; case IF_DELETE_HOOK: if_master.if_delete_hook = func; break; default: break; } } /* Interface existance check by index. */ struct interface * if_lookup_by_index (unsigned int index) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { if (ifp->ifindex == index) return ifp; } return NULL; } const char * ifindex2ifname (unsigned int index) { struct interface *ifp; return ((ifp = if_lookup_by_index(index)) != NULL) ? ifp->name : "unknown"; } unsigned int ifname2ifindex (const char *name) { struct interface *ifp; return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp->ifindex : IFINDEX_INTERNAL; } /* Interface existance check by interface name. */ struct interface * if_lookup_by_name (const char *name) { struct listnode *node; struct interface *ifp; if (name) for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { if (strcmp(name, ifp->name) == 0) return ifp; } return NULL; } struct interface * if_lookup_by_name_len(const char *name, size_t namelen) { struct listnode *node; struct interface *ifp; if (namelen > INTERFACE_NAMSIZ) return NULL; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0')) return ifp; } return NULL; } /* Lookup interface by IPv4 address. */ struct interface * if_lookup_exact_address (struct in_addr src) { struct listnode *node; struct listnode *cnode; struct interface *ifp; struct prefix *p; struct connected *c; for (ALL_LIST_ELEMENTS_RO (iflist, 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; } /* Lookup interface by IPv4 address. */ struct interface * if_lookup_address (struct in_addr src) { 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 (iflist, 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; } /* Get interface by name if given name interface doesn't exist create one. */ struct interface * if_get_by_name (const char *name) { struct interface *ifp; return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp : if_create(name, strlen(name)); } struct interface * if_get_by_name_len(const char *name, size_t namelen) { struct interface *ifp; return ((ifp = if_lookup_by_name_len(name, namelen)) != NULL) ? ifp : if_create(name, namelen); } /* 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; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c)) zlog_info ("Interface %s index %d metric %d mtu %d " #ifdef HAVE_IPV6 "mtu6 %d " #endif /* HAVE_IPV6 */ "%s", ifp->name, 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 listnode *node; void *p; for (ALL_LIST_ELEMENTS_RO (iflist, 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) { struct interface *ifp; size_t seppos = 0; if ( (ifp = if_lookup_by_name_len(name, nlen)) != 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 (name, seppos); else return if_get_by_name_len (name, nlen); } #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; 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; } #ifdef SUNOS_5 ifp = if_sunwzebra_get (argv[0], sl); #else ifp = if_get_by_name_len(argv[0], sl); #endif /* SUNOS_5 */ vty->index = ifp; vty->node = INTERFACE_NODE; return CMD_SUCCESS; } 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; ifp = if_lookup_by_name (argv[0]); 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; } /* 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; for (ALL_LIST_ELEMENTS_RO (iflist, 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 %s %s/%d ", str, ifp->name, prefix_family_str (p), inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); p = connected->destination; if (p) { strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), BUFSIZ - strlen(logbuf)); } zlog (NULL, LOG_INFO, "%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 unsigned int 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 (unsigned int 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, unsigned int 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 (void) { iflist = list_new (); #if 0 ifaddr_ipv4_table = route_table_init (); #endif /* ifaddr_ipv4_table */ if (iflist) { iflist->cmp = (int (*)(void *, void *))if_cmp_func; return; } memset (&if_master, 0, sizeof if_master); } void if_terminate (void) { for (;;) { struct interface *ifp; ifp = listnode_head (iflist); if (ifp == NULL) break; if_delete (ifp); } list_delete (iflist); iflist = NULL; } quagga-0.99.22.4/lib/if.h0000644000175000017500000002517612177450262011563 00000000000000/* Interface related header. Copyright (C) 1997, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_IF_H #define _ZEBRA_IF_H #include "linklist.h" /* Interface name length. Linux define value in /usr/include/linux/if.h. #define IFNAMSIZ 16 FreeBSD define value in /usr/include/net/if.h. #define IFNAMSIZ 16 */ #define INTERFACE_NAMSIZ 20 #define INTERFACE_HWADDR_MAX 20 #ifdef HAVE_PROC_NET_DEV struct if_stats { unsigned long rx_packets; /* total packets received */ unsigned long tx_packets; /* total packets transmitted */ unsigned long rx_bytes; /* total bytes received */ unsigned long tx_bytes; /* total bytes transmitted */ unsigned long rx_errors; /* bad packets received */ unsigned long tx_errors; /* packet transmit problems */ unsigned long rx_dropped; /* no space in linux buffers */ unsigned long tx_dropped; /* no space available in linux */ unsigned long rx_multicast; /* multicast packets received */ unsigned long rx_compressed; unsigned long tx_compressed; unsigned long collisions; /* detailed rx_errors: */ unsigned long rx_length_errors; unsigned long rx_over_errors; /* receiver ring buff overflow */ unsigned long rx_crc_errors; /* recved pkt with crc error */ unsigned long rx_frame_errors; /* recv'd frame alignment error */ unsigned long rx_fifo_errors; /* recv'r fifo overrun */ unsigned long rx_missed_errors; /* receiver missed packet */ /* detailed tx_errors */ unsigned long tx_aborted_errors; unsigned long tx_carrier_errors; unsigned long tx_fifo_errors; unsigned long tx_heartbeat_errors; unsigned long tx_window_errors; }; #endif /* HAVE_PROC_NET_DEV */ /* Interface structure */ struct interface { /* Interface name. 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). */ unsigned int 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 */ /* Hardware address. */ #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; }; #else unsigned short hw_type; u_char hw_addr[INTERFACE_HWADDR_MAX]; int hw_addr_len; #endif /* HAVE_STRUCT_SOCKADDR_DL */ /* interface bandwidth, kbits */ unsigned int bandwidth; /* description of the interface. */ char *desc; /* Distribute list. */ void *distribute_in; void *distribute_out; /* Connected address list. */ 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 */ }; /* 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) /* The ZEBRA_IFC_REAL flag should be set if and only if this address exists in the kernel. The ZEBRA_IFC_CONFIGURED flag should be set if and only if this address was configured by the user from inside quagga. */ /* Flags for connected address. */ u_char flags; #define ZEBRA_IFA_SECONDARY (1 << 0) #define ZEBRA_IFA_PEER (1 << 1) /* 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 (unsigned int); extern struct interface *if_lookup_exact_address (struct in_addr); extern struct interface *if_lookup_address (struct in_addr); /* 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); /* 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); /* 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 (void); extern void if_terminate (void); extern void if_dump_all (void); extern const char *if_flag_dump(unsigned long); /* 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 (unsigned int); /* Please use ifname2ifindex instead of if_nametoindex where possible; ifname2ifindex uses internal interface info, whereas if_nametoindex must make a system call. */ extern unsigned int ifname2ifindex(const char *ifname); /* 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 unsigned int if_nametoindex (const char *); #endif #ifndef HAVE_IF_INDEXTONAME extern char *if_indextoname (unsigned int, char *); #endif /* 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_pseudo_cmd; extern struct cmd_element no_interface_pseudo_cmd; extern struct cmd_element show_address_cmd; #endif /* _ZEBRA_IF_H */ quagga-0.99.22.4/lib/if_rmap.c0000644000175000017500000001704412132522417012561 00000000000000/* 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-0.99.22.4/lib/if_rmap.h0000644000175000017500000000253412132522417012564 00000000000000/* 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-0.99.22.4/lib/jhash.c0000644000175000017500000000717712112613214012241 00000000000000/* 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 (void *key, u_int32_t length, u_int32_t initval) { u_int32_t a, b, c, len; 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 (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-0.99.22.4/lib/jhash.h0000644000175000017500000000307112112613214012233 00000000000000/* 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(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(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-0.99.22.4/lib/keychain.c0000644000175000017500000005776112132522417012751 00000000000000/* 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,MIN,MAX) \ { \ unsigned long tmpl; \ char *endptr = NULL; \ tmpl = strtoul ((STR), &endptr, 10); \ if (*endptr != '\0' || tmpl == ULONG_MAX) \ return -1; \ if ( tmpl < (MIN) || tmpl > (MAX)) \ return -1; \ (V) = tmpl; \ } /* 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_RANGE (hour, time_str, 0, 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_RANGE (min, time_str, 0, 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_RANGE (sec, time_str, 0, 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-0.99.22.4/lib/keychain.h0000644000175000017500000000270012132522417012735 00000000000000/* 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-0.99.22.4/lib/linklist.c0000644000175000017500000001352212132522417012772 00000000000000/* 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++; } /* 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-0.99.22.4/lib/linklist.h0000644000175000017500000001132112177450262013001 00000000000000/* 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 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; \ 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-0.99.22.4/lib/log.c0000644000175000017500000005443412177450262011740 00000000000000/* * 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", "MASC", 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) { 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. */ 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); } 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 ); #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 if (((size = backtrace(array,array_size(array)) <= 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; if (((size = backtrace(array,array_size(array))) <= 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_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); 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), }; #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 /* 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_MASC } 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); /* 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. */ extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, char *buf, size_t buflen); /* 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[40]; /* 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-0.99.22.4/lib/md5.c0000644000175000017500000003052712176415342011640 00000000000000/* $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 */ caddr_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-0.99.22.4/lib/md5.h0000644000175000017500000000575112177450262011647 00000000000000/* $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, caddr_t digest); #endif /* ! _LIBZEBRA_MD5_H_*/ quagga-0.99.22.4/lib/memory.c0000644000175000017500000003614412177450262012465 00000000000000/* * 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 occured. */ 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. */ void * zcalloc (int type, size_t size) { void *memory; memory = calloc (1, size); if (memory == NULL) zerror ("calloc", type, size); alloc_inc (type); return memory; } /* * Given a pointer returned by zmalloc or zcalloc, free it and * return a pointer to a new size, basically acting like realloc(). * Requires: ptr was returned by zmalloc, zcalloc, 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; 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, zcalloc, 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 = zcalloc (type, size); mtype_log ("xcalloc", memory, file, line, type); return memory; } void * mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size) { void *memory; /* Realloc need before allocated pointer. */ mstat[type].t_realloc++; memory = zrealloc (type, ptr, size); mtype_log ("xrealloc", memory, file, line, type); return memory; } /* Important function. */ void mtype_zfree (const char *file, int line, int type, void *ptr) { mstat[type].t_free++; mtype_log ("xfree", ptr, file, line, type); zfree (type, ptr); } char * mtype_zstrdup (const char *file, int line, int type, 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_all, show_memory_all_cmd, "show memory all", "Show running system information\n" "Memory statistics\n" "All 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; } ALIAS (show_memory_all, show_memory_cmd, "show memory", "Show running system information\n" "Memory statistics\n") DEFUN (show_memory_lib, show_memory_lib_cmd, "show memory lib", SHOW_STR "Memory statistics\n" "Library memory\n") { show_memory_vty (vty, memory_list_lib); return CMD_SUCCESS; } DEFUN (show_memory_zebra, show_memory_zebra_cmd, "show memory zebra", SHOW_STR "Memory statistics\n" "Zebra memory\n") { show_memory_vty (vty, memory_list_zebra); return CMD_SUCCESS; } DEFUN (show_memory_rip, show_memory_rip_cmd, "show memory rip", SHOW_STR "Memory statistics\n" "RIP memory\n") { show_memory_vty (vty, memory_list_rip); return CMD_SUCCESS; } DEFUN (show_memory_ripng, show_memory_ripng_cmd, "show memory ripng", SHOW_STR "Memory statistics\n" "RIPng memory\n") { show_memory_vty (vty, memory_list_ripng); return CMD_SUCCESS; } DEFUN (show_memory_babel, show_memory_babel_cmd, "show memory babel", SHOW_STR "Memory statistics\n" "Babel memory\n") { show_memory_vty (vty, memory_list_babel); return CMD_SUCCESS; } DEFUN (show_memory_bgp, show_memory_bgp_cmd, "show memory bgp", SHOW_STR "Memory statistics\n" "BGP memory\n") { show_memory_vty (vty, memory_list_bgp); return CMD_SUCCESS; } DEFUN (show_memory_ospf, show_memory_ospf_cmd, "show memory ospf", SHOW_STR "Memory statistics\n" "OSPF memory\n") { show_memory_vty (vty, memory_list_ospf); return CMD_SUCCESS; } DEFUN (show_memory_ospf6, show_memory_ospf6_cmd, "show memory ospf6", SHOW_STR "Memory statistics\n" "OSPF6 memory\n") { show_memory_vty (vty, memory_list_ospf6); return CMD_SUCCESS; } DEFUN (show_memory_isis, show_memory_isis_cmd, "show memory isis", SHOW_STR "Memory statistics\n" "ISIS memory\n") { show_memory_vty (vty, memory_list_isis); return CMD_SUCCESS; } void memory_init (void) { install_element (RESTRICTED_NODE, &show_memory_cmd); install_element (RESTRICTED_NODE, &show_memory_all_cmd); install_element (RESTRICTED_NODE, &show_memory_lib_cmd); install_element (RESTRICTED_NODE, &show_memory_rip_cmd); install_element (RESTRICTED_NODE, &show_memory_ripng_cmd); install_element (RESTRICTED_NODE, &show_memory_babel_cmd); install_element (RESTRICTED_NODE, &show_memory_bgp_cmd); install_element (RESTRICTED_NODE, &show_memory_ospf_cmd); install_element (RESTRICTED_NODE, &show_memory_ospf6_cmd); install_element (RESTRICTED_NODE, &show_memory_isis_cmd); install_element (VIEW_NODE, &show_memory_cmd); install_element (VIEW_NODE, &show_memory_all_cmd); install_element (VIEW_NODE, &show_memory_lib_cmd); install_element (VIEW_NODE, &show_memory_rip_cmd); install_element (VIEW_NODE, &show_memory_ripng_cmd); install_element (VIEW_NODE, &show_memory_babel_cmd); install_element (VIEW_NODE, &show_memory_bgp_cmd); install_element (VIEW_NODE, &show_memory_ospf_cmd); install_element (VIEW_NODE, &show_memory_ospf6_cmd); install_element (VIEW_NODE, &show_memory_isis_cmd); install_element (ENABLE_NODE, &show_memory_cmd); install_element (ENABLE_NODE, &show_memory_all_cmd); install_element (ENABLE_NODE, &show_memory_lib_cmd); install_element (ENABLE_NODE, &show_memory_zebra_cmd); install_element (ENABLE_NODE, &show_memory_rip_cmd); install_element (ENABLE_NODE, &show_memory_ripng_cmd); install_element (ENABLE_NODE, &show_memory_babel_cmd); install_element (ENABLE_NODE, &show_memory_bgp_cmd); install_element (ENABLE_NODE, &show_memory_ospf_cmd); install_element (ENABLE_NODE, &show_memory_ospf6_cmd); install_element (ENABLE_NODE, &show_memory_isis_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 t, g, m, k; /* easy cases */ if (!bytes) return "0 bytes"; if (bytes == 1) return "1 byte"; if (sizeof (unsigned long) >= 8) /* Hacked to make it not warn on ILP32 machines * Shift will always be 40 at runtime. See below too */ t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0); else t = 0; g = bytes >> 30; m = bytes >> 20; k = bytes >> 10; if (t > 10) { /* The shift will always be 39 at runtime. * Just hacked to make it not warn on 'smaller' machines. * Static compiler analysis should mean no extra code */ if (bytes & (1UL << (sizeof (unsigned long) >= 8 ? 39 : 0))) t++; snprintf (buf, len, "%4d TiB", t); } else if (g > 10) { if (bytes & (1 << 29)) g++; snprintf (buf, len, "%d GiB", g); } else 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-0.99.22.4/lib/memory.h0000644000175000017500000000623612177450262012471 00000000000000/* 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) zcalloc ((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 *zcalloc (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-0.99.22.4/lib/memtypes.awk0000644000175000017500000000430412132522417013342 00000000000000# $Id: memtypes.awk,v 1.4 2006/03/30 14:30:19 paul Exp $ # # 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-0.99.22.4/lib/memtypes.c0000644000175000017500000002424712177450262013021 00000000000000/* * 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_DESC, "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" }, { -1, NULL }, }; struct memory_list memory_list_zebra[] = { { MTYPE_RTADV_PREFIX, "Router Advertisement Prefix" }, { MTYPE_VRF, "VRF" }, { MTYPE_VRF_NAME, "VRF name" }, { MTYPE_NEXTHOP, "Nexthop" }, { MTYPE_RIB, "RIB" }, { MTYPE_RIB_QUEUE, "RIB process work queue" }, { MTYPE_STATIC_IPV4, "Static IPv4 route" }, { MTYPE_STATIC_IPV6, "Static IPv6 route" }, { MTYPE_RIB_DEST, "RIB destination" }, { MTYPE_RIB_TABLE_INFO, "RIB table info" }, { -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" }, { -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" }, { -1, NULL }, }; struct memory_list memory_list_ospf6[] = { { MTYPE_OSPF6_TOP, "OSPF6 top" }, { MTYPE_OSPF6_AREA, "OSPF6 area" }, { MTYPE_OSPF6_IF, "OSPF6 interface" }, { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor" }, { MTYPE_OSPF6_ROUTE, "OSPF6 route" }, { MTYPE_OSPF6_PREFIX, "OSPF6 prefix" }, { MTYPE_OSPF6_MESSAGE, "OSPF6 message" }, { MTYPE_OSPF6_LSA, "OSPF6 LSA" }, { MTYPE_OSPF6_LSA_SUMMARY, "OSPF6 LSA summary" }, { MTYPE_OSPF6_LSDB, "OSPF6 LSA database" }, { MTYPE_OSPF6_VERTEX, "OSPF6 vertex" }, { MTYPE_OSPF6_SPFTREE, "OSPF6 SPF tree" }, { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop" }, { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info" }, { MTYPE_OSPF6_OTHER, "OSPF6 other" }, { -1, NULL }, }; struct memory_list memory_list_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" }, { -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" }, { NULL, NULL}, }; quagga-0.99.22.4/lib/memtypes.h0000644000175000017500000001112012200224470012773 00000000000000/* 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_DESC, 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_RTADV_PREFIX, MTYPE_VRF, MTYPE_VRF_NAME, MTYPE_NEXTHOP, MTYPE_RIB, MTYPE_RIB_QUEUE, MTYPE_STATIC_IPV4, MTYPE_STATIC_IPV6, MTYPE_RIB_DEST, MTYPE_RIB_TABLE_INFO, 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_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_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_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_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_vtysh[]; #endif /* _QUAGGA_MEMTYPES_H */ quagga-0.99.22.4/lib/network.c0000644000175000017500000000404412132522417012631 00000000000000/* * 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; } quagga-0.99.22.4/lib/network.h0000644000175000017500000000264012132522417012636 00000000000000/* * 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)) #endif /* _ZEBRA_NETWORK_H */ quagga-0.99.22.4/lib/pid_output.c0000644000175000017500000000523512132522417013337 00000000000000/* * 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-0.99.22.4/lib/plist.c0000644000175000017500000023145612132522417012304 00000000000000/* 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" /* Each prefix-list's entry. */ struct prefix_list_entry { int seq; int le; int ge; enum prefix_list_type type; int any; struct prefix prefix; unsigned long refcnt; unsigned long hitcnt; struct prefix_list_entry *next; struct prefix_list_entry *prev; }; /* List of struct prefix_list. */ struct prefix_list_list { struct prefix_list *head; struct prefix_list *tail; }; /* Master structure of prefix_list. */ struct prefix_master { /* List of prefix_list which name is number. */ struct prefix_list_list num; /* List of prefix_list which name is string. */ struct prefix_list_list str; /* Whether sequential number is used. */ int seqnum; /* The latest update. */ struct prefix_list *recent; /* Hook function which is executed when new prefix_list is added. */ void (*add_hook) (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 = { {NULL, NULL}, {NULL, NULL}, 1, NULL, NULL, }; static struct prefix_master * prefix_master_get (afi_t afi) { if (afi == AFI_IP) return &prefix_master_ipv4; #ifdef HAVE_IPV6 else if (afi == AFI_IP6) return &prefix_master_ipv6; #endif /* HAVE_IPV6 */ else if (afi == AFI_ORF_PREFIX) return &prefix_master_orf; return NULL; } /* Lookup prefix_list from list of prefix_list by name. */ struct prefix_list * prefix_list_lookup (afi_t afi, const char *name) { struct prefix_list *plist; struct prefix_master *master; if (name == NULL) return NULL; master = prefix_master_get (afi); if (master == NULL) return NULL; for (plist = master->num.head; plist; plist = plist->next) if (strcmp (plist->name, name) == 0) return plist; for (plist = master->str.head; plist; plist = plist->next) if (strcmp (plist->name, name) == 0) return plist; return NULL; } 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, 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); 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, const char *name) { struct prefix_list *plist; plist = prefix_list_lookup (afi, name); if (plist == NULL) plist = prefix_list_insert (afi, name); return plist; } /* Delete prefix-list from prefix_list_master and free it. */ 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; /* Sequential number. */ if (seq) seqnum = atoi (seq); /* ge and le number */ if (ge) genum = atoi (ge); if (le) lenum = atoi (le); /* Check filter type. */ if (strncmp ("permit", typestr, 1) == 0) type = PREFIX_PERMIT; else if (strncmp ("deny", typestr, 1) == 0) type = PREFIX_DENY; else { vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE); return CMD_WARNING; } /* "any" is special token for matching any IPv4 addresses. */ if (afi == AFI_IP) { if (strncmp ("any", prefix, strlen (prefix)) == 0) { ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p); genum = 0; lenum = IPV4_MAX_BITLEN; any = 1; } else ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE); return CMD_WARNING; } } #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { if (strncmp ("any", prefix, strlen (prefix)) == 0) { ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p); genum = 0; lenum = IPV6_MAX_BITLEN; any = 1; } else ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } } #endif /* HAVE_IPV6 */ /* ge and le check. */ if (genum && genum <= p.prefixlen) return vty_invalid_prefix_range (vty, prefix); if (lenum && lenum <= p.prefixlen) return vty_invalid_prefix_range (vty, prefix); if (lenum && genum > lenum) return vty_invalid_prefix_range (vty, prefix); if (genum && lenum == (afi == AFI_IP ? 32 : 128)) lenum = 0; /* Get prefix_list with name. */ plist = prefix_list_get (afi, name); /* Make prefix entry. */ pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any); /* Check same policy. */ dup = prefix_entry_dup_check (plist, pentry); if (dup) { prefix_list_entry_free (pentry); vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s", VTY_NEWLINE); vty_out (vty, " seq %d %s %s", dup->seq, typestr, prefix); if (! any && genum) vty_out (vty, " ge %d", genum); if (! any && lenum) vty_out (vty, " le %d", lenum); vty_out (vty, "%s", VTY_NEWLINE); return CMD_WARNING; } /* Install new filter to the access_list. */ prefix_list_entry_add (plist, pentry); return CMD_SUCCESS; } 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); 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); 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, 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, 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); 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_ORF_PREFIX, name); if (! plist) return CMD_WARNING; if (set) { pentry = prefix_list_entry_make (&orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY), orfp->seq, orfp->le, orfp->ge, 0); if (prefix_entry_dup_check (plist, pentry)) { prefix_list_entry_free (pentry); return CMD_WARNING; } prefix_list_entry_add (plist, pentry); } else { pentry = prefix_list_entry_lookup (plist, &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY), orfp->seq, orfp->le, orfp->ge); if (! pentry) return CMD_WARNING; prefix_list_entry_delete (plist, pentry, 1); } return CMD_SUCCESS; } void prefix_bgp_orf_remove_all (char *name) { struct prefix_list *plist; plist = prefix_list_lookup (AFI_ORF_PREFIX, name); if (plist) prefix_list_delete (plist); } /* return prefix count */ int prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name) { struct prefix_list *plist; struct prefix_list_entry *pentry; plist = prefix_list_lookup (AFI_ORF_PREFIX, name); if (! plist) return 0; if (! vty) return plist->count; vty_out (vty, "ip%s prefix-list %s: %d entries%s", afi == AFI_IP ? "" : "v6", plist->name, plist->count, VTY_NEWLINE); for (pentry = plist->head; pentry; pentry = pentry->next) { struct prefix *p = &pentry->prefix; char buf[BUFSIZ]; vty_out (vty, " seq %d %s %s/%d", pentry->seq, prefix_list_type_str (pentry), inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); if (pentry->ge) vty_out (vty, " ge %d", pentry->ge); if (pentry->le) vty_out (vty, " le %d", pentry->le); vty_out (vty, "%s", VTY_NEWLINE); } return plist->count; } static void prefix_list_reset_orf (void) { struct prefix_list *plist; struct prefix_list *next; struct prefix_master *master; master = prefix_master_get (AFI_ORF_PREFIX); if (master == NULL) return; for (plist = master->num.head; plist; plist = next) { next = plist->next; prefix_list_delete (plist); } for (plist = master->str.head; plist; plist = next) { next = plist->next; prefix_list_delete (plist); } assert (master->num.head == NULL); assert (master->num.tail == NULL); assert (master->str.head == NULL); assert (master->str.tail == NULL); master->seqnum = 1; master->recent = NULL; } /* Prefix-list node. */ 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_reset_ipv4 (void) { struct prefix_list *plist; struct prefix_list *next; struct prefix_master *master; master = prefix_master_get (AFI_IP); if (master == NULL) return; for (plist = master->num.head; plist; plist = next) { next = plist->next; prefix_list_delete (plist); } for (plist = master->str.head; plist; plist = next) { next = plist->next; prefix_list_delete (plist); } assert (master->num.head == NULL); assert (master->num.tail == NULL); assert (master->str.head == NULL); assert (master->str.tail == NULL); master->seqnum = 1; master->recent = NULL; } 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, &show_ip_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd); install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd); install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd); } #ifdef HAVE_IPV6 /* Prefix-list node. */ 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_reset_ipv6 (void) { struct prefix_list *plist; struct prefix_list *next; struct prefix_master *master; master = prefix_master_get (AFI_IP6); if (master == NULL) return; for (plist = master->num.head; plist; plist = next) { next = plist->next; prefix_list_delete (plist); } for (plist = master->str.head; plist; plist = next) { next = plist->next; prefix_list_delete (plist); } assert (master->num.head == NULL); assert (master->num.tail == NULL); assert (master->str.head == NULL); assert (master->str.tail == NULL); master->seqnum = 1; master->recent = NULL; } 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, &show_ipv6_prefix_list_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd); } #endif /* HAVE_IPV6 */ void prefix_list_init () { prefix_list_init_ipv4 (); #ifdef HAVE_IPV6 prefix_list_init_ipv6 (); #endif /* HAVE_IPV6 */ } void prefix_list_reset () { prefix_list_reset_ipv4 (); #ifdef HAVE_IPV6 prefix_list_reset_ipv6 (); #endif /* HAVE_IPV6 */ prefix_list_reset_orf (); } quagga-0.99.22.4/lib/plist.h0000644000175000017500000000425212132522417012301 00000000000000/* * 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 #define AFI_ORF_PREFIX 65535 enum prefix_list_type { PREFIX_DENY, PREFIX_PERMIT, }; enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER }; struct prefix_list { char *name; char *desc; struct prefix_master *master; enum prefix_name_type type; int count; int rangecount; struct prefix_list_entry *head; struct prefix_list_entry *tail; struct prefix_list *next; struct prefix_list *prev; }; struct orf_prefix { u_int32_t seq; u_char ge; u_char le; struct prefix p; }; /* Prototypes. */ 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 struct prefix_list *prefix_list_lookup (afi_t, const char *); extern enum prefix_list_type prefix_list_apply (struct prefix_list *, void *); 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 (char *); extern int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *); #endif /* _QUAGGA_PLIST_H */ quagga-0.99.22.4/lib/pqueue.c0000644000175000017500000001136512132522417012450 00000000000000/* 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; } quagga-0.99.22.4/lib/pqueue.h0000644000175000017500000000253712000052240012440 00000000000000/* 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 trickle_down (int index, struct pqueue *queue); extern void trickle_up (int index, struct pqueue *queue); #endif /* _ZEBRA_PQUEUE_H */ quagga-0.99.22.4/lib/prefix.c0000644000175000017500000010075412177450262012451 00000000000000/* * 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); } /* 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 */ 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 */ return 0; } /* 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 { 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 */ } 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 */ 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; } /* 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 (0, (pnt - str) + 1); strncpy (cp, str, pnt - str); *(cp + (pnt - str)) = '\0'; ret = inet_pton (AF_INET6, cp, &p->prefix); free (cp); if (ret == 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) { if (su->sa.sa_family == AF_INET) { struct prefix_ipv4 *p; p = prefix_ipv4_new (); p->family = AF_INET; p->prefix = su->sin.sin_addr; p->prefixlen = IPV4_MAX_BITLEN; return (struct prefix *) p; } #ifdef HAVE_IPV6 if (su->sa.sa_family == AF_INET6) { struct prefix_ipv6 *p; p = prefix_ipv6_new (); p->family = AF_INET6; p->prefixlen = IPV6_MAX_BITLEN; memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr)); return (struct prefix *) p; } #endif /* HAVE_IPV6 */ return NULL; } 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 */ } 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 */ return 0; } int prefix2str (const struct prefix *p, char *str, int size) { char buf[BUFSIZ]; inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ); snprintf (str, size, "%s/%d", buf, p->prefixlen); return 0; } struct prefix * prefix_new () { struct prefix *p; p = XCALLOC (MTYPE_PREFIX, sizeof *p); return p; } /* Free prefix structure. */ void prefix_free (struct prefix *p) { XFREE (MTYPE_PREFIX, p); } /* Utility function. Check the string only contains digit * character. * 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-0.99.22.4/lib/prefix.h0000644000175000017500000001465712132522417012455 00000000000000/* * 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 #include "sockunion.h" /* * 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. */ /* IPv4 and IPv6 unified prefix structure. */ struct prefix { u_char family; u_char prefixlen; union { u_char prefix; struct in_addr prefix4; #ifdef HAVE_IPV6 struct in6_addr prefix6; #endif /* HAVE_IPV6 */ struct { struct in_addr id; struct in_addr adv_router; } lp; u_char val[8]; } u __attribute__ ((aligned (8))); }; /* IPv4 prefix structure. */ struct prefix_ipv4 { u_char family; u_char prefixlen; struct in_addr prefix __attribute__ ((aligned (8))); }; /* IPv6 prefix structure. */ #ifdef HAVE_IPV6 struct prefix_ipv6 { u_char family; u_char prefixlen; struct in6_addr prefix __attribute__ ((aligned (8))); }; #endif /* HAVE_IPV6 */ struct prefix_ls { u_char family; u_char prefixlen; struct in_addr id __attribute__ ((aligned (8))); struct in_addr adv_router; }; /* Prefix for routing distinguisher. */ struct prefix_rd { u_char family; u_char prefixlen; u_char val[8] __attribute__ ((aligned (8))); }; #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif /* INET_ADDRSTRLEN */ #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif /* INET6_ADDRSTRLEN */ #ifndef INET6_BUFSIZ #define INET6_BUFSIZ 51 #endif /* INET6_BUFSIZ */ /* Max bit/byte length of IPv4 address. */ #define IPV4_MAX_BYTELEN 4 #define IPV4_MAX_BITLEN 32 #define IPV4_MAX_PREFIXLEN 32 #define IPV4_ADDR_CMP(D,S) memcmp ((D), (S), IPV4_MAX_BYTELEN) #define IPV4_ADDR_SAME(D,S) (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0) #define IPV4_ADDR_COPY(D,S) memcpy ((D), (S), IPV4_MAX_BYTELEN) #define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000) #define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000) #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) /* Prototypes. */ extern int afi2family (afi_t); extern afi_t family2afi (int); /* 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 int prefix2str (const struct prefix *, 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 *); extern void prefix2sockunion (const struct prefix *, union sockunion *); 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 *); #endif /* _ZEBRA_PREFIX_H */ quagga-0.99.22.4/lib/privs.c0000644000175000017500000005244412132522417012312 00000000000000/* * Zebra privileges. * * Copyright (C) 2003 Paul Jakma. * 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 "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] = { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST }, }, [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] = { 2, (pvalue_t []) { PRIV_FILE_DAC_EXECUTE, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH, 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) ) { fprintf (stderr, "privs_init: initial cap_set_proc failed\n"); 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 */ /* 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) { /* 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 caps!", __func__); exit (1); } /* to raise: copy original permitted into our working effective set * to lower: just clear the working effective set */ if (op == ZPRIVS_RAISE) priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps); else if (op == ZPRIVS_LOWER) priv_emptyset (zprivs_state.caps); else return -1; if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 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_isemptyset (effective) == B_TRUE) result = ZPRIVS_LOWERED; else result = ZPRIVS_RAISED; } if (effective) priv_freeset (effective); return result; } static void zprivs_caps_init (struct zebra_privs_t *zprivs) { pset_t *basic; pset_t *empty; /* 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); /* we need an empty set for 'effective', potentially for inheritable too */ if ( (empty = priv_allocset()) == NULL) { fprintf (stderr, "%s: couldn't get empty set!\n", __func__); exit (1); } priv_emptyset (empty); /* 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); } /* now clear the effective set and we're ready to go */ if (setppriv (PRIV_SET, PRIV_EFFECTIVE, empty)) { fprintf (stderr, "%s: error setting effective set!, %s\n", __func__, safe_strerror (errno) ); exit (1); } /* we'll use this as our working-storage privset */ zprivs_state.caps = empty; /* 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 */ priv_emptyset (zprivs_state.caps); 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; } void zprivs_init(struct zebra_privs_t *zprivs) { struct passwd *pwentry = NULL; struct group *grentry = NULL; 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)) ) { zprivs_state.zuid = pwentry->pw_uid; } else { /* cant use log.h here as it depends on vty */ fprintf (stderr, "privs_init: could not lookup user %s\n", zprivs->user); exit (1); } } grentry = NULL; 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; if ( setgroups (1, &zprivs_state.vtygrp) ) { fprintf (stderr, "privs_init: could not setgroups, %s\n", safe_strerror (errno) ); exit (1); } } else { fprintf (stderr, "privs_init: could not lookup vty group %s\n", zprivs->vty_group); exit (1); } } if (zprivs->group) { if ( (grentry = getgrnam (zprivs->group)) ) { zprivs_state.zgid = grentry->gr_gid; } else { fprintf (stderr, "privs_init: could not lookup group %s\n", zprivs->group); exit (1); } /* 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-0.99.22.4/lib/privs.h0000644000175000017500000000505012132522417012306 00000000000000/* * 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-0.99.22.4/lib/queue.h0000644000175000017500000005201012177450262012274 00000000000000/*- * 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_ #include /* * 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-0.99.22.4/lib/regex-gnu.h0000644000175000017500000005030312132522417013045 00000000000000/* 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-0.99.22.4/lib/regex.c0000644000175000017500000056112112132522417012256 00000000000000/* 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 occured while computing the fastmap, just forget about it. */ free (preg->fastmap); preg->fastmap = NULL; } } return (int) ret; } #ifdef _LIBC weak_alias (__regcomp, regcomp) #endif /* regexec searches for a given pattern, specified by PREG, in the string STRING. If NMATCH is zero or REG_NOSUB was set in the cflags argument to `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at least NMATCH elements, and we set them to the offsets of the corresponding matched substrings. EFLAGS specifies `execution flags' which affect matching: if REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. We return 0 if we find a match and REG_NOMATCH if not. */ int regexec (preg, string, nmatch, pmatch, eflags) const regex_t *preg; const char *string; size_t nmatch; regmatch_t pmatch[]; int eflags; { int ret; struct re_registers regs; regex_t private_preg; int len = strlen (string); boolean want_reg_info = !preg->no_sub && nmatch > 0; private_preg = *preg; private_preg.not_bol = !!(eflags & REG_NOTBOL); private_preg.not_eol = !!(eflags & REG_NOTEOL); /* The user has told us exactly how many registers to return information about, via `nmatch'. We have to pass that on to the matching routines. */ private_preg.regs_allocated = REGS_FIXED; if (want_reg_info) { regs.num_regs = nmatch; regs.start = TALLOC (nmatch * 2, regoff_t); if (regs.start == NULL) return (int) REG_NOMATCH; regs.end = regs.start + nmatch; } /* Perform the searching operation. */ ret = re_search (&private_preg, string, len, /* start: */ 0, /* range: */ len, want_reg_info ? ®s : (struct re_registers *) 0); /* Copy the register information to the POSIX structure. */ if (want_reg_info) { if (ret >= 0) { unsigned r; for (r = 0; r < nmatch; r++) { pmatch[r].rm_so = regs.start[r]; pmatch[r].rm_eo = regs.end[r]; } } /* If we needed the temporary register info, free the space now. */ free (regs.start); } /* We want zero return to mean success, unlike `re_search'. */ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; } #ifdef _LIBC weak_alias (__regexec, regexec) #endif /* Returns a message corresponding to an error code, ERRCODE, returned from either regcomp or regexec. We don't use PREG here. */ size_t regerror (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-0.99.22.4/lib/route_types.h0000644000175000017500000002432612200224470013526 00000000000000/* 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_HSLS 10 #define ZEBRA_ROUTE_OLSR 11 #define ZEBRA_ROUTE_BABEL 12 #define ZEBRA_ROUTE_MAX 13 #define SHOW_ROUTE_V4_HEADER \ "Codes: K - kernel route, C - connected, S - static, R - RIP,%s" \ " O - OSPF, I - IS-IS, B - BGP, A - Babel,%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,%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)" #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" #define QUAGGA_IP_REDIST_STR_BABELD \ "(kernel|connected|static|rip|ospf|isis|bgp)" #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" #define QUAGGA_IP6_REDIST_STR_BABELD \ "(kernel|connected|static|ripng|ospf6|isis|bgp)" #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" /* bgpd */ #define QUAGGA_REDIST_STR_BGPD \ "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|babel)" #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" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP_REDIST_STR_BGPD \ "(kernel|connected|static|rip|ospf|isis|babel)" #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" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP6_REDIST_STR_BGPD \ "(kernel|connected|static|ripng|ospf6|isis|babel)" #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" /* isisd */ #define QUAGGA_REDIST_STR_ISISD \ "(kernel|connected|static|rip|ripng|ospf|ospf6|bgp|babel)" #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" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP_REDIST_STR_ISISD \ "(kernel|connected|static|rip|ospf|bgp|babel)" #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" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP6_REDIST_STR_ISISD \ "(kernel|connected|static|ripng|ospf6|bgp|babel)" #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" /* ospf6d */ #define QUAGGA_REDIST_STR_OSPF6D \ "(kernel|connected|static|ripng|isis|bgp|babel)" #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" /* ospfd */ #define QUAGGA_REDIST_STR_OSPFD \ "(kernel|connected|static|rip|isis|bgp|babel)" #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" \ "Babel routing protocol (Babel)\n" /* ripd */ #define QUAGGA_REDIST_STR_RIPD \ "(kernel|connected|static|ospf|isis|bgp|babel)" #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" \ "Babel routing protocol (Babel)\n" /* ripngd */ #define QUAGGA_REDIST_STR_RIPNGD \ "(kernel|connected|static|ospf6|isis|bgp|babel)" #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" /* zebra */ #define QUAGGA_REDIST_STR_ZEBRA \ "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp|babel)" #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" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP_REDIST_STR_ZEBRA \ "(kernel|connected|static|rip|ospf|isis|bgp|babel)" #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" \ "Babel routing protocol (Babel)\n" #define QUAGGA_IP6_REDIST_STR_ZEBRA \ "(kernel|connected|static|ripng|ospf6|isis|bgp|babel)" #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" #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_HSLS, "hsls", 'H' ), DESC_ENTRY (ZEBRA_ROUTE_OLSR, "olsr", 'o' ), DESC_ENTRY (ZEBRA_ROUTE_BABEL, "babel", 'A' ), }; #undef DESC_ENTRY #endif /* QUAGGA_DEFINE_DESC_TABLE */ #endif /* _QUAGGA_ROUTE_TYPES_H */ quagga-0.99.22.4/lib/route_types.pl0000755000175000017500000001226512101110036013704 00000000000000#!/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; } /* 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 }; /* 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-0.99.22.4/lib/routemap.h0000644000175000017500000001172412177450262013013 00000000000000/* Route map function. * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_ROUTEMAP_H #define _ZEBRA_ROUTEMAP_H /* Route map's type. */ enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY }; typedef enum { RMAP_MATCH, RMAP_DENYMATCH, RMAP_NOMATCH, RMAP_ERROR, RMAP_OKAY } route_map_result_t; typedef enum { RMAP_RIP, RMAP_RIPNG, RMAP_BABEL, RMAP_OSPF, RMAP_OSPF6, RMAP_BGP, RMAP_ZEBRA } 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 *)); #endif /* _ZEBRA_ROUTEMAP_H */ quagga-0.99.22.4/lib/sigevent.c0000644000175000017500000001651312177450262012777 00000000000000/* 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 #ifdef REG_EIP if (context) return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]); #endif /* REG_EIP */ #endif /* GNU_LINUX */ #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 ); 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-0.99.22.4/lib/sigevent.h0000644000175000017500000000315312177450262013000 00000000000000/* * 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-0.99.22.4/lib/smux.c0000644000175000017500000010746012177450262012151 00000000000000/* 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 *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 (master, smux_connect, NULL, 0); break; case SMUX_CONNECT: smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10); break; case SMUX_READ: smux_read_thread = thread_add_read (master, smux_read, NULL, sock); break; default: break; } } 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 */ 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-0.99.22.4/lib/smux.h0000644000175000017500000000711312177450262012150 00000000000000/* 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 /* 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; \ static struct in_addr snmp_in_addr_val; #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 (oid *, int, 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-0.99.22.4/lib/snmp.c0000644000175000017500000000575012177450262012131 00000000000000/* 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 (oid *o1, int o1_len, oid *o2, int o2_len) { int i; for (i = 0; i < min (o1_len, o2_len); i++) { if (o1[i] < o2[i]) return -1; else if (o1[i] > o2[i]) return 1; } if (o1_len < o2_len) return -1; if (o1_len > o2_len) return 1; return 0; } 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-0.99.22.4/lib/sockopt.c0000644000175000017500000004300712132522417012624 00000000000000/* setsockopt functions * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "log.h" #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, unsigned int 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, unsigned int 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)); #else #error "Unsupported multicast API" #endif } static int setsockopt_ipv4_ifindex (int sock, int 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, int 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 int getsockopt_ipv4_ifindex (struct msghdr *msgh) { /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */ int 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. */ int *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 */ int 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_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-0.99.22.4/lib/sockopt.h0000644000175000017500000000757112132522417012637 00000000000000/* 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, unsigned int ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, unsigned int mcast_addr, unsigned int 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, int); extern int 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_signature(int sock, union sockunion *su, const char *password); #endif /*_ZEBRA_SOCKOPT_H */ quagga-0.99.22.4/lib/sockunion.c0000644000175000017500000004040612177450262013161 00000000000000/* Socket union related function. * Copyright (c) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "vty.h" #include "sockunion.h" #include "memory.h" #include "str.h" #include "log.h" #ifndef HAVE_INET_ATON int inet_aton (const char *cp, struct in_addr *inaddr) { int dots = 0; register u_long addr = 0; register u_long val = 0, base = 10; do { register char c = *cp; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': val = (val * base) + (c - '0'); break; case '.': if (++dots > 3) return 0; case '\0': if (val > 255) return 0; addr = addr << 8 | val; val = 0; break; default: return 0; } } while (*cp++) ; if (dots < 3) addr <<= 8 * (3 - dots); if (inaddr) inaddr->s_addr = htonl (addr); return 1; } #endif /* ! HAVE_INET_ATON */ #ifndef HAVE_INET_PTON int inet_pton (int family, const char *strptr, void *addrptr) { if (family == AF_INET) { struct in_addr in_val; if (inet_aton (strptr, &in_val)) { memcpy (addrptr, &in_val, sizeof (struct in_addr)); return 1; } return 0; } errno = EAFNOSUPPORT; return -1; } #endif /* ! HAVE_INET_PTON */ #ifndef HAVE_INET_NTOP const char * inet_ntop (int family, const void *addrptr, char *strptr, size_t len) { unsigned char *p = (unsigned char *) addrptr; if (family == AF_INET) { char temp[INET_ADDRSTRLEN]; snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); if (strlen(temp) >= len) { errno = ENOSPC; return NULL; } strcpy(strptr, temp); return strptr; } errno = EAFNOSUPPORT; return NULL; } #endif /* ! HAVE_INET_NTOP */ const char * inet_sutop (union sockunion *su, char *str) { switch (su->sa.sa_family) { case AF_INET: inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN); break; #ifdef HAVE_IPV6 case AF_INET6: inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN); break; #endif /* HAVE_IPV6 */ } return str; } int str2sockunion (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 (union sockunion *su, char *buf, size_t len) { if (su->sa.sa_family == AF_INET) return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); #ifdef HAVE_IPV6 else if (su->sa.sa_family == AF_INET6) return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); #endif /* HAVE_IPV6 */ return NULL; } union sockunion * sockunion_str2su (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 (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 (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 (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 occured 0 : connect success 1 : connect is in progress */ enum connect_result sockunion_connect (int fd, union sockunion *peersu, unsigned short port, unsigned int ifindex) { int ret; int val; union sockunion su; memcpy (&su, peersu, sizeof (union sockunion)); switch (su.sa.sa_family) { case AF_INET: su.sin.sin_port = port; break; #ifdef HAVE_IPV6 case AF_INET6: su.sin6.sin6_port = port; #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) { #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID /* su.sin6.sin6_scope_id = ifindex; */ #ifdef MUSICA su.sin6.sin6_scope_id = ifindex; #endif #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */ #ifndef MUSICA SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); #endif } #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) { #if defined(LINUX_IPV6) || defined(NRL) memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr)); #else su->sin6.sin6_addr = in6addr_any; #endif /* LINUX_IPV6 */ } } #endif /* HAVE_IPV6 */ ret = bind (sock, (struct sockaddr *)su, size); if (ret < 0) zlog (NULL, LOG_WARNING, "can't bind socket : %s", 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 (union sockunion *su1, union sockunion *su2) { int ret = 0; if (su1->sa.sa_family != su2->sa.sa_family) return 0; switch (su1->sa.sa_family) { case AF_INET: ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr, sizeof (struct in_addr)); break; #ifdef HAVE_IPV6 case AF_INET6: ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr, sizeof (struct in6_addr)); break; #endif /* HAVE_IPV6 */ } if (ret == 0) return 1; else return 0; } /* After TCP connection is established. Get local address and port. */ union sockunion * sockunion_getsockname (int fd) { int ret; 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 (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 (struct in6_addr *addr1, 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 (union sockunion *su1, union sockunion *su2) { if (su1->sa.sa_family > su2->sa.sa_family) return 1; if (su1->sa.sa_family < su2->sa.sa_family) return -1; if (su1->sa.sa_family == AF_INET) { if (ntohl (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 (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-0.99.22.4/lib/sockunion.h0000644000175000017500000000760512177450262013172 00000000000000/* * Socket union header. * Copyright (c) 1997 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_SOCKUNION_H #define _ZEBRA_SOCKUNION_H #if 0 union sockunion { struct sockinet { u_char si_len; u_char si_family; u_short si_port; } su_si; struct sockaddr_in su_sin; struct sockaddr_in6 su_sin6; }; #define su_len su_si.si_len #define su_family su_si.si_family #define su_port su_si.si_port #endif /* 0 */ union sockunion { struct sockaddr sa; struct sockaddr_in sin; #ifdef HAVE_IPV6 struct sockaddr_in6 sin6; #endif /* HAVE_IPV6 */ }; enum connect_result { connect_error, connect_success, connect_in_progress }; /* Default address family. */ #ifdef HAVE_IPV6 #define AF_INET_UNION AF_INET6 #else #define AF_INET_UNION AF_INET #endif /* Sockunion address string length. Same as INET6_ADDRSTRLEN. */ #define SU_ADDRSTRLEN 46 /* Macro to set link local index to the IPv6 address. For KAME IPv6 stack. */ #ifdef KAME #define IN6_LINKLOCAL_IFINDEX(a) ((a).s6_addr[2] << 8 | (a).s6_addr[3]) #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ do { \ (a).s6_addr[2] = ((i) >> 8) & 0xff; \ (a).s6_addr[3] = (i) & 0xff; \ } while (0) #else #define IN6_LINKLOCAL_IFINDEX(a) #define SET_IN6_LINKLOCAL_IFINDEX(a, i) #endif /* KAME */ #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 (union sockunion *, char *, size_t); extern int sockunion_cmp (union sockunion *, union sockunion *); extern int sockunion_same (union sockunion *, union sockunion *); 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 (union sockunion *su); extern const char *inet_sutop (union sockunion *su, char *str); extern enum connect_result sockunion_connect (int fd, union sockunion *su, unsigned short port, unsigned int); extern union sockunion *sockunion_getsockname (int); extern union sockunion *sockunion_getpeername (int); extern union sockunion *sockunion_dup (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-0.99.22.4/lib/str.c0000644000175000017500000000430112132522417011744 00000000000000/* * 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. */ #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-0.99.22.4/lib/str.h0000644000175000017500000000117712000052240011743 00000000000000/* * $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-0.99.22.4/lib/stream.c0000644000175000017500000004626012211704467012446 00000000000000 /* * 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", \ (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)); } 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; } /* 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_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) { STREAM_BOUND_WARN (s, "put"); return 0; } stream_putc (s, 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; } /* Read size from fd. */ int stream_read_unblock (struct stream *s, int fd, size_t size) { int nbytes; int val; STREAM_VERIFY_SANE(s); if (STREAM_WRITEABLE (s) < size) { STREAM_BOUND_WARN (s, "put"); return 0; } val = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, val|O_NONBLOCK); nbytes = read (fd, s->data + s->endp, size); fcntl (fd, F_SETFL, val); 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; } /* 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-0.99.22.4/lib/stream.h0000644000175000017500000002041312211704467012443 00000000000000/* * 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) /* 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 *); 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 *); #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); /* Deprecated: all file descriptors should already be non-blocking. Will be removed. Use stream_read_try instead. */ extern int stream_read_unblock (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 *); 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-0.99.22.4/lib/table.c0000644000175000017500000004167012177450262012244 00000000000000/* * 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, 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 (struct prefix *n, struct prefix *p, struct prefix *new) { int i; u_char diff; u_char mask; u_char *np = (u_char *)&n->u.prefix; u_char *pp = (u_char *)&p->u.prefix; u_char *newp = (u_char *)&new->u.prefix; for (i = 0; i < p->prefixlen / 8; i++) { if (np[i] == pp[i]) newp[i] = np[i]; else break; } new->prefixlen = i * 8; if (new->prefixlen != p->prefixlen) { diff = np[i] ^ pp[i]; mask = 0x80; while (new->prefixlen < p->prefixlen && !(mask & diff)) { mask >>= 1; new->prefixlen++; } newp[i] = np[i] & maskbit[new->prefixlen % 8]; } } 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, 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, 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; u_char prefixlen; int cmp; prefixlen = p->prefixlen; 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-0.99.22.4/lib/table.h0000644000175000017500000001407712177450262012252 00000000000000/* * 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, struct prefix *); extern struct route_node *route_node_lookup (const struct route_table *, 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-0.99.22.4/lib/thread.c0000644000175000017500000010025512211704467012415 00000000000000/* Thread management routine * Copyright (C) 1998, 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* #define DEBUG */ #include #include "thread.h" #include "memory.h" #include "log.h" #include "hash.h" #include "command.h" #include "sigevent.h" #if defined HAVE_SNMP && defined SNMP_AGENTX #include #include #include #include extern int agentx_enabled; #endif #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); } static unsigned long timeval_elapsed (struct timeval a, struct timeval b) { return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + (a.tv_usec - b.tv_usec)); } #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; strcpy(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); strcpy(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; } /* List allocation and head/tail print out. */ static void thread_list_debug (struct thread_list *list) { printf ("count [%d] head [%p] tail [%p]\n", list->count, list->head, list->tail); } /* Debug print for thread_master. */ static void __attribute__ ((unused)) thread_master_debug (struct thread_master *m) { printf ("-----------\n"); printf ("readlist : "); thread_list_debug (&m->read); printf ("writelist : "); thread_list_debug (&m->write); printf ("timerlist : "); thread_list_debug (&m->timer); printf ("eventlist : "); thread_list_debug (&m->event); printf ("unuselist : "); thread_list_debug (&m->unuse); printf ("bgndlist : "); thread_list_debug (&m->background); printf ("total alloc: [%ld]\n", m->alloc); printf ("-----------\n"); } /* Allocate new thread master. */ struct thread_master * thread_master_create () { if (cpu_record == NULL) cpu_record = hash_create_size (1011, (unsigned int (*) (void *))cpu_record_hash_key, (int (*) (const void *, const void *))cpu_record_hash_cmp); return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, sizeof (struct thread_master)); } /* Add a new thread to the list. */ static void thread_list_add (struct thread_list *list, struct thread *thread) { thread->next = NULL; thread->prev = list->tail; if (list->tail) list->tail->next = thread; else list->head = thread; list->tail = thread; list->count++; } /* Add a new thread just before the point. */ static void thread_list_add_before (struct thread_list *list, struct thread *point, struct thread *thread) { thread->next = point; thread->prev = point->prev; if (point->prev) point->prev->next = thread; else list->head = thread; point->prev = thread; list->count++; } /* Delete a thread from the list. */ static struct thread * thread_list_delete (struct thread_list *list, struct thread *thread) { if (thread->next) thread->next->prev = thread->prev; else list->tail = thread->prev; if (thread->prev) thread->prev->next = thread->next; else list->head = thread->next; thread->next = thread->prev = NULL; list->count--; return thread; } /* Move thread to unuse list. */ static void thread_add_unuse (struct thread_master *m, struct thread *thread) { assert (m != NULL && thread != NULL); assert (thread->next == NULL); assert (thread->prev == NULL); assert (thread->type == THREAD_UNUSED); thread_list_add (&m->unuse, thread); /* XXX: Should we deallocate funcname here? */ } /* Free all unused thread. */ static void thread_list_free (struct thread_master *m, struct thread_list *list) { struct thread *t; struct thread *next; for (t = list->head; t; t = next) { next = t->next; XFREE (MTYPE_THREAD, t); list->count--; m->alloc--; } } /* Stop thread scheduler. */ void thread_master_free (struct thread_master *m) { thread_list_free (m, &m->read); thread_list_free (m, &m->write); thread_list_free (m, &m->timer); thread_list_free (m, &m->event); thread_list_free (m, &m->ready); thread_list_free (m, &m->unuse); thread_list_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; } /* Trim blankspace and "()"s */ void strip_funcname (char *dest, const char *funcname) { char buff[FUNCNAME_LEN]; char tmp, *e, *b = buff; strncpy(buff, funcname, sizeof(buff)); buff[ sizeof(buff) -1] = '\0'; e = buff +strlen(buff) -1; /* Wont work for funcname == "Word (explanation)" */ while (*b == ' ' || *b == '(') ++b; while (*e == ' ' || *e == ')') --e; e++; tmp = *e; *e = '\0'; strcpy (dest, b); *e = tmp; } /* Get new thread. */ static struct thread * thread_get (struct thread_master *m, u_char type, int (*func) (struct thread *), void *arg, const char* funcname) { 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; strip_funcname (thread->funcname, funcname); return thread; } /* Add new read thread. */ struct thread * funcname_thread_add_read (struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, const char* funcname) { struct thread *thread; assert (m != NULL); if (FD_ISSET (fd, &m->readfd)) { zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd); return NULL; } thread = thread_get (m, THREAD_READ, func, arg, funcname); FD_SET (fd, &m->readfd); thread->u.fd = fd; thread_list_add (&m->read, thread); return thread; } /* Add new write thread. */ struct thread * funcname_thread_add_write (struct thread_master *m, int (*func) (struct thread *), void *arg, int fd, const char* funcname) { struct thread *thread; assert (m != NULL); if (FD_ISSET (fd, &m->writefd)) { zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd); return NULL; } thread = thread_get (m, THREAD_WRITE, func, arg, funcname); FD_SET (fd, &m->writefd); thread->u.fd = fd; thread_list_add (&m->write, thread); return thread; } static struct thread * funcname_thread_add_timer_timeval (struct thread_master *m, int (*func) (struct thread *), int type, void *arg, struct timeval *time_relative, const char* funcname) { struct thread *thread; struct thread_list *list; struct timeval alarm_time; struct thread *tt; assert (m != NULL); assert (type == THREAD_TIMER || type == THREAD_BACKGROUND); assert (time_relative); list = ((type == THREAD_TIMER) ? &m->timer : &m->background); thread = thread_get (m, type, func, arg, funcname); /* 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); /* Sort by timeval. */ for (tt = list->head; tt; tt = tt->next) if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) break; if (tt) thread_list_add_before (list, tt, thread); else thread_list_add (list, thread); return thread; } /* Add timer event thread. */ struct thread * funcname_thread_add_timer (struct thread_master *m, int (*func) (struct thread *), void *arg, long timer, const char* funcname) { 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, funcname); } /* 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, const char* funcname) { 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, funcname); } /* 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, const char *funcname) { 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, funcname); } /* Add simple event thread. */ struct thread * funcname_thread_add_event (struct thread_master *m, int (*func) (struct thread *), void *arg, int val, const char* funcname) { struct thread *thread; assert (m != NULL); thread = thread_get (m, THREAD_EVENT, func, arg, funcname); 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; switch (thread->type) { case THREAD_READ: assert (FD_ISSET (thread->u.fd, &thread->master->readfd)); FD_CLR (thread->u.fd, &thread->master->readfd); list = &thread->master->read; break; case THREAD_WRITE: assert (FD_ISSET (thread->u.fd, &thread->master->writefd)); FD_CLR (thread->u.fd, &thread->master->writefd); list = &thread->master->write; break; case THREAD_TIMER: list = &thread->master->timer; break; case THREAD_EVENT: list = &thread->master->event; break; case THREAD_READY: list = &thread->master->ready; break; case THREAD_BACKGROUND: list = &thread->master->background; break; default: return; break; } thread_list_delete (list, thread); thread->type = THREAD_UNUSED; thread_add_unuse (thread->master, 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); t->type = THREAD_UNUSED; thread_add_unuse (m, 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); t->type = THREAD_UNUSED; thread_add_unuse (m, t); } } return ret; } static struct timeval * thread_timer_wait (struct thread_list *tlist, struct timeval *timer_val) { if (!thread_empty (tlist)) { *timer_val = timeval_subtract (tlist->head->u.sands, relative_time); return timer_val; } return NULL; } static struct thread * thread_run (struct thread_master *m, struct thread *thread, struct thread *fetch) { *fetch = *thread; thread->type = THREAD_UNUSED; thread_add_unuse (m, thread); return fetch; } static int thread_process_fd (struct thread_list *list, fd_set *fdset, fd_set *mfdset) { struct thread *thread; struct thread *next; int ready = 0; assert (list); for (thread = list->head; thread; thread = next) { next = thread->next; if (FD_ISSET (THREAD_FD (thread), fdset)) { assert (FD_ISSET (THREAD_FD (thread), mfdset)); FD_CLR(THREAD_FD (thread), mfdset); thread_list_delete (list, thread); thread_list_add (&thread->master->ready, thread); thread->type = THREAD_READY; ready++; } } return ready; } /* Add all timers that have popped to the ready list. */ static unsigned int thread_timer_process (struct thread_list *list, struct timeval *timenow) { struct thread *thread; struct thread *next; unsigned int ready = 0; for (thread = list->head; thread; thread = next) { next = thread->next; if (timeval_cmp (*timenow, thread->u.sands) < 0) return ready; thread_list_delete (list, thread); 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. */ struct thread * thread_fetch (struct thread_master *m, struct thread *fetch) { struct thread *thread; fd_set readfd; fd_set writefd; 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; #if defined HAVE_SNMP && defined SNMP_AGENTX struct timeval snmp_timer_wait; int snmpblock = 0; int fdsetsize; #endif /* 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_run (m, thread, fetch); /* 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 = m->readfd; writefd = m->writefd; exceptfd = 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; } #if defined HAVE_SNMP && defined SNMP_AGENTX /* When SNMP is enabled, we may have to select() on additional FD. snmp_select_info() will add them to `readfd'. The trick with this function is its last argument. We need to set it to 0 if timer_wait is not NULL and we need to use the provided new timer only if it is still set to 0. */ if (agentx_enabled) { fdsetsize = FD_SETSIZE; snmpblock = 1; if (timer_wait) { snmpblock = 0; memcpy(&snmp_timer_wait, timer_wait, sizeof(struct timeval)); } snmp_select_info(&fdsetsize, &readfd, &snmp_timer_wait, &snmpblock); if (snmpblock == 0) timer_wait = &snmp_timer_wait; } #endif num = 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; } #if defined HAVE_SNMP && defined SNMP_AGENTX if (agentx_enabled) { if (num > 0) snmp_read(&readfd); else if (num == 0) { snmp_timeout(); run_alarms(); } netsnmp_check_outstanding_agent_requests(); } #endif /* 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) { /* Normal priority read thead. */ thread_process_fd (&m->read, &readfd, &m->readfd); /* Write thead. */ thread_process_fd (&m->write, &writefd, &m->writefd); } #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_run (m, thread, fetch); #endif /* Background timer/events, lowest priority */ thread_timer_process (&m->background, &relative_time); if ((thread = thread_trim_head (&m->ready)) != NULL) return thread_run (m, thread, fetch); } } 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); return (timeval_elapsed(relative_time, thread->real) > THREAD_YIELD_TIME_SLOT); } 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 */ } /* 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. */ 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; strcpy(tmp.funcname, thread->funcname); thread->hist = hash_get (cpu_record, &tmp, (void * (*) (void *))cpu_record_hash_alloc); } GETRUSAGE (&before); thread->real = before.real; (*thread->func) (thread); 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 */ } /* Execute thread */ struct thread * funcname_thread_execute (struct thread_master *m, int (*func)(struct thread *), void *arg, int val, const char* funcname) { 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; strip_funcname (dummy.funcname, funcname); thread_call (&dummy); return NULL; } quagga-0.99.22.4/lib/thread.h0000644000175000017500000001727112177450262012431 00000000000000/* Thread management routine header. * Copyright (C) 1998 Kunihiro Ishiguro * Portions Copyright (c) 2008 Everton da Silva Marques * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU 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; }; /* Master of the theads. */ struct thread_master { struct thread_list read; struct thread_list write; struct thread_list timer; struct thread_list event; struct thread_list ready; struct thread_list unuse; struct thread_list background; fd_set readfd; fd_set writefd; fd_set exceptfd; unsigned long alloc; }; typedef unsigned char thread_type; /* ISO C99 maximum function name length is 63 */ #define FUNCNAME_LEN 64 /* 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; struct timeval real; struct cpu_thread_history *hist; /* cache pointer to cpu_history */ char funcname[FUNCNAME_LEN]; }; 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; char funcname[FUNCNAME_LEN]; }; /* 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 thread_add_read(m,f,a,v) funcname_thread_add_read(m,f,a,v,#f) #define thread_add_write(m,f,a,v) funcname_thread_add_write(m,f,a,v,#f) #define thread_add_timer(m,f,a,v) funcname_thread_add_timer(m,f,a,v,#f) #define thread_add_timer_msec(m,f,a,v) funcname_thread_add_timer_msec(m,f,a,v,#f) #define thread_add_event(m,f,a,v) funcname_thread_add_event(m,f,a,v,#f) #define thread_execute(m,f,a,v) funcname_thread_execute(m,f,a,v,#f) /* 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) /* 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, const char*); extern struct thread *funcname_thread_add_write (struct thread_master *, int (*)(struct thread *), void *, int, const char*); extern struct thread *funcname_thread_add_timer (struct thread_master *, int (*)(struct thread *), void *, long, const char*); extern struct thread *funcname_thread_add_timer_msec (struct thread_master *, int (*)(struct thread *), void *, long, const char*); extern struct thread *funcname_thread_add_event (struct thread_master *, int (*)(struct thread *), void *, int, const char*); extern struct thread *funcname_thread_add_background (struct thread_master *, int (*func)(struct thread *), void *arg, long milliseconds_to_delay, const char *funcname); extern struct thread *funcname_thread_execute (struct thread_master *, int (*)(struct thread *), void *, int, const char *); extern void thread_cancel (struct thread *); extern unsigned int thread_cancel_event (struct thread_master *, void *); extern struct thread *thread_fetch (struct thread_master *, struct thread *); extern void thread_call (struct thread *); extern unsigned long thread_timer_remain_second (struct thread *); extern int thread_should_yield (struct thread *); /* 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); #endif /* _ZEBRA_THREAD_H */ quagga-0.99.22.4/lib/vector.c0000644000175000017500000000737012132522417012447 00000000000000/* 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-0.99.22.4/lib/vector.h0000644000175000017500000000425012132522417012446 00000000000000/* * 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-0.99.22.4/lib/version.h0000644000175000017500000000267012211704553012636 00000000000000/* 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 "0.99.22.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." pid_t pid_output (const char *); #ifndef HAVE_DAEMON int daemon(int, int); #endif #endif /* _ZEBRA_VERSION_H */ quagga-0.99.22.4/lib/version.h.in0000644000175000017500000000263012177450262013245 00000000000000/* @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." pid_t pid_output (const char *); #ifndef HAVE_DAEMON int daemon(int, int); #endif #endif /* _ZEBRA_VERSION_H */ quagga-0.99.22.4/lib/vty.c0000644000175000017500000020247512177450262012001 00000000000000/* * 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 /* 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; /* 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->fd, 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 [25]; 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; /* 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); } /* Ensure length of input buffer. Is buffer is short, double it. */ static void vty_ensure (struct vty *vty, int length) { if (vty->max <= length) { vty->max *= 2; vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max); } } /* Basic function to insert character into vty. */ static void vty_self_insert (struct vty *vty, char c) { int i; int length; vty_ensure (vty, vty->length + 1); length = vty->length - vty->cp; memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); vty->buf[vty->cp] = c; vty_write (vty, &vty->buf[vty->cp], length + 1); for (i = 0; i < length; i++) vty_write (vty, &telnet_backward_char, 1); vty->cp++; vty->length++; } /* Self insert character 'c' in overwrite mode. */ static void vty_self_insert_overwrite (struct vty *vty, char c) { vty_ensure (vty, vty->length + 1); vty->buf[vty->cp++] = c; if (vty->cp > vty->length) vty->length++; if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) return; vty_write (vty, &c, 1); } /* Insert a word into vty interface with overwrite mode. */ static void vty_insert_word_overwrite (struct vty *vty, char *str) { int len = strlen (str); vty_write (vty, str, len); strcpy (&vty->buf[vty->cp], str); vty->cp += len; vty->length = vty->cp; } /* Forward character. */ static void vty_forward_char (struct vty *vty) { if (vty->cp < vty->length) { vty_write (vty, &vty->buf[vty->cp], 1); vty->cp++; } } /* Backward character. */ static void vty_backward_char (struct vty *vty) { if (vty->cp > 0) { vty->cp--; vty_write (vty, &telnet_backward_char, 1); } } /* Move to the beginning of the line. */ static void vty_beginning_of_line (struct vty *vty) { while (vty->cp) vty_backward_char (vty); } /* Move to the end of the line. */ static void vty_end_of_line (struct vty *vty) { while (vty->cp < vty->length) vty_forward_char (vty); } static void vty_kill_line_from_beginning (struct vty *); static void vty_redraw_line (struct vty *); /* Print command line history. This function is called from vty_next_line and vty_previous_line. */ static void vty_history_print (struct vty *vty) { int length; vty_kill_line_from_beginning (vty); /* Get previous line from history buffer */ length = strlen (vty->hist[vty->hp]); memcpy (vty->buf, vty->hist[vty->hp], length); vty->cp = vty->length = length; /* Redraw current line */ vty_redraw_line (vty); } /* Show next command line history. */ 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; } /* 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_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 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? */ 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; } /* Kill line from the beginning. */ static void vty_kill_line_from_beginning (struct vty *vty) { vty_beginning_of_line (vty); vty_kill_line (vty); } /* Delete a word before the point. */ static void vty_forward_kill_word (struct vty *vty) { while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') vty_delete_char (vty); while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') vty_delete_char (vty); } /* Delete a word before the point. */ static void vty_backward_kill_word (struct vty *vty) { while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') vty_delete_backward_char (vty); while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') vty_delete_backward_char (vty); } /* Transpose chars before or at the point. */ static void vty_transpose_chars (struct vty *vty) { char c1, c2; /* If length is short or point is near by the beginning of line then return. */ if (vty->length < 2 || vty->cp < 1) return; /* In case of point is located at the end of the line. */ if (vty->cp == vty->length) { c1 = vty->buf[vty->cp - 1]; c2 = vty->buf[vty->cp - 2]; vty_backward_char (vty); vty_backward_char (vty); vty_self_insert_overwrite (vty, c1); vty_self_insert_overwrite (vty, c2); } else { c1 = vty->buf[vty->cp]; c2 = vty->buf[vty->cp - 1]; vty_backward_char (vty); vty_self_insert_overwrite (vty, c1); vty_self_insert_overwrite (vty, c2); } } /* Do completion at vty interface. */ static void vty_complete_command (struct vty *vty) { int i; int ret; char **matched = NULL; vector vline; if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) return; vline = cmd_make_strvec (vty->buf); if (vline == NULL) return; /* In case of 'help \t'. */ if (isspace ((int) vty->buf[vty->length - 1])) vector_set (vline, '\0'); matched = cmd_complete_command (vline, vty, &ret); cmd_free_strvec (vline); vty_out (vty, "%s", VTY_NEWLINE); switch (ret) { case CMD_ERR_AMBIGUOUS: vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); vty_prompt (vty); vty_redraw_line (vty); break; case CMD_ERR_NO_MATCH: /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ vty_prompt (vty); vty_redraw_line (vty); break; case CMD_COMPLETE_FULL_MATCH: vty_prompt (vty); vty_redraw_line (vty); vty_backward_pure_word (vty); vty_insert_word_overwrite (vty, matched[0]); vty_self_insert (vty, ' '); XFREE (MTYPE_TMP, matched[0]); break; case CMD_COMPLETE_MATCH: vty_prompt (vty); vty_redraw_line (vty); vty_backward_pure_word (vty); vty_insert_word_overwrite (vty, matched[0]); XFREE (MTYPE_TMP, matched[0]); vector_only_index_free (matched); return; break; case CMD_COMPLETE_LIST_MATCH: for (i = 0; matched[i] != NULL; i++) { if (i != 0 && ((i % 6) == 0)) vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-10s ", matched[i]); XFREE (MTYPE_TMP, matched[i]); } vty_out (vty, "%s", VTY_NEWLINE); vty_prompt (vty); vty_redraw_line (vty); break; case CMD_ERR_NOTHING_TODO: vty_prompt (vty); vty_redraw_line (vty); break; default: break; } if (matched) vector_only_index_free (matched); } static void vty_describe_fold (struct vty *vty, int cmd_width, unsigned int desc_width, struct desc *desc) { char *buf; const char *cmd, *p; int pos; cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; if (desc_width <= 0) { vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); return; } buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1); for (p = desc->str; strlen (p) > desc_width; p += pos + 1) { for (pos = desc_width; pos > 0; pos--) if (*(p + pos) == ' ') break; if (pos == 0) break; strncpy (buf, p, pos); buf[pos] = '\0'; vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); cmd = ""; } vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); XFREE (MTYPE_TMP, buf); } /* Describe matched command function. */ static void vty_describe_command (struct vty *vty) { int ret; vector vline; vector describe; unsigned int i, width, desc_width; struct desc *desc, *desc_cr = NULL; vline = cmd_make_strvec (vty->buf); /* In case of '> ?'. */ if (vline == NULL) { vline = vector_init (1); vector_set (vline, '\0'); } else if (isspace ((int) vty->buf[vty->length - 1])) vector_set (vline, '\0'); describe = cmd_describe_command (vline, vty, &ret); vty_out (vty, "%s", VTY_NEWLINE); /* Ambiguous error. */ switch (ret) { case CMD_ERR_AMBIGUOUS: 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 ((desc = vector_slot (describe, i)) != NULL) { unsigned int len; if (desc->cmd[0] == '\0') continue; len = strlen (desc->cmd); if (desc->cmd[0] == '.') len--; if (width < len) width = len; } /* Get width of description string. */ desc_width = vty->width - (width + 6); /* Print out description. */ for (i = 0; i < vector_active (describe); i++) if ((desc = vector_slot (describe, i)) != NULL) { if (desc->cmd[0] == '\0') continue; if (strcmp (desc->cmd, command_cr) == 0) { desc_cr = desc; continue; } if (!desc->str) vty_out (vty, " %-s%s", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, VTY_NEWLINE); else if (desc_width >= strlen (desc->str)) vty_out (vty, " %-*s %s%s", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str, VTY_NEWLINE); else vty_describe_fold (vty, width, desc_width, desc); #if 0 vty_out (vty, " %-*s %s%s", width desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str ? desc->str : "", VTY_NEWLINE); #endif /* 0 */ } if ((desc = desc_cr)) { if (!desc->str) vty_out (vty, " %-s%s", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, VTY_NEWLINE); else if (desc_width >= strlen (desc->str)) vty_out (vty, " %-*s %s%s", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str, VTY_NEWLINE); else vty_describe_fold (vty, width, desc_width, desc); } 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 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 #define VTY_ESCAPE 2 /* Escape character command map. */ static void vty_escape_map (unsigned char c, struct vty *vty) { switch (c) { case ('A'): vty_previous_line (vty); break; case ('B'): vty_next_line (vty); break; case ('C'): vty_forward_char (vty); break; case ('D'): vty_backward_char (vty); break; default: break; } /* Go back to normal mode. */ vty->escape = VTY_NORMAL; } /* Quit print out to the buffer. */ static void vty_buffer_reset (struct vty *vty) { buffer_reset (vty->obuf); vty_prompt (vty); vty_redraw_line (vty); } /* Read data via vty socket. */ static int vty_read (struct thread *thread) { int i; int 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; } /* Pre-escape status. */ if (vty->escape == VTY_PRE_ESCAPE) { switch (buf[i]) { case '[': vty->escape = VTY_ESCAPE; break; case 'b': vty_backward_word (vty); vty->escape = VTY_NORMAL; break; case 'f': vty_forward_word (vty); vty->escape = VTY_NORMAL; break; case 'd': vty_forward_kill_word (vty); vty->escape = VTY_NORMAL; break; case CONTROL('H'): case 0x7f: vty_backward_kill_word (vty); vty->escape = VTY_NORMAL; break; default: vty->escape = VTY_NORMAL; break; } continue; } switch (buf[i]) { case CONTROL('A'): vty_beginning_of_line (vty); break; case CONTROL('B'): vty_backward_char (vty); break; case CONTROL('C'): vty_stop_input (vty); break; case CONTROL('D'): vty_delete_char (vty); break; case CONTROL('E'): vty_end_of_line (vty); break; case CONTROL('F'): vty_forward_char (vty); break; case CONTROL('H'): case 0x7f: vty_delete_backward_char (vty); break; case CONTROL('K'): vty_kill_line (vty); break; case CONTROL('N'): vty_next_line (vty); break; case CONTROL('P'): vty_previous_line (vty); break; case CONTROL('T'): vty_transpose_chars (vty); break; case CONTROL('U'): vty_kill_line_from_beginning (vty); break; case CONTROL('W'): vty_backward_kill_word (vty); break; case CONTROL('Z'): vty_end_config (vty); break; case '\n': case '\r': vty_out (vty, "%s", VTY_NEWLINE); vty_execute (vty); break; case '\t': vty_complete_command (vty); break; case '?': if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) vty_self_insert (vty, buf[i]); else vty_describe_command (vty); break; case '\033': if (i + 1 < nbytes && buf[i + 1] == '[') { vty->escape = VTY_ESCAPE; i++; } else vty->escape = VTY_PRE_ESCAPE; break; default: if (buf[i] > 31 && buf[i] < 127) vty_self_insert (vty, buf[i]); break; } } /* Check status. */ if (vty->status == VTY_CLOSE) vty_close (vty); else { vty_event (VTY_WRITE, vty_sock, vty); vty_event (VTY_READ, vty_sock, vty); } return 0; } /* Flush buffer to the vty. */ static int vty_flush (struct thread *thread) { int erase; 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)) flushrc = buffer_flush_available(vty->obuf, vty->fd); else if (vty->status == VTY_MORELINE) flushrc = buffer_flush_window(vty->obuf, vty->fd, vty->width, 1, erase, 0); else flushrc = buffer_flush_window(vty->obuf, vty->fd, 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; } /* 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 (); vty->fd = vty_sock; vty->type = VTY_TERM; 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; } else vty->node = AUTH_NODE; vty->fail = 0; vty->cp = 0; vty_clear_buf (vty); vty->length = 0; memset (vty->hist, 0, sizeof (vty->hist)); vty->hp = 0; vty->hindex = 0; vector_set_index (vtyvec, vty_sock, vty); vty->status = VTY_NORMAL; vty->v_timeout = vty_timeout_val; if (host.lines >= 0) vty->lines = host.lines; else vty->lines = -1; vty->iac = 0; vty->iac_sb_in_progress = 0; vty->sb_len = 0; if (! no_password_check) { /* Vty is not available if password isn't set. */ if (host.password == NULL && host.password_encrypt == NULL) { vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); vty->status = VTY_CLOSE; vty_close (vty); return NULL; } } /* Say hello to the world. */ vty_hello (vty); if (! no_password_check) vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); /* Setting up terminal. */ vty_will_echo (vty); vty_will_suppress_go_ahead (vty); vty_dont_linemode (vty); vty_do_window_size (vty); /* vty_dont_lflow_ahead (vty); */ vty_prompt (vty); /* Add read/write thread. */ vty_event (VTY_WRITE, vty_sock, vty); vty_event (VTY_READ, vty_sock, vty); return vty; } /* Accept connection from the network. */ static int vty_accept (struct thread *thread) { int vty_sock; union sockunion su; int ret; unsigned int on; int accept_sock; struct prefix *p = NULL; 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); p = sockunion2hostprefix (&su); /* VTY's accesslist apply. */ if (p->family == AF_INET && vty_accesslist_name) { if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && (access_list_apply (acl, p) == FILTER_DENY)) { 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); prefix_free (p); return 0; } } #ifdef HAVE_IPV6 /* VTY's ipv6 accesslist apply. */ if (p->family == AF_INET6 && vty_ipv6_accesslist_name) { if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && (access_list_apply (acl, p) == FILTER_DENY)) { 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); prefix_free (p); return 0; } } #endif /* HAVE_IPV6 */ prefix_free (p); on = 1; ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof (on)); if (ret < 0) zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", safe_strerror (errno)); zlog (NULL, LOG_INFO, "Vty connection from %s", sockunion2str (&su, buf, SU_ADDRSTRLEN)); vty_create (vty_sock, &su); return 0; } #if defined(HAVE_IPV6) && !defined(NRL) 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 && ! NRL */ /* 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; #ifdef HAVE_IPV6 case AF_INET6: naddr=&su.sin6.sin6_addr; #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 && ! NRL */ #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->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->fd)) { case BUFFER_PENDING: vty_event(VTYSH_WRITE, vty->fd, 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 */ for (p = buf; p < buf+nbytes; p++) { vty_ensure(vty, vty->length+1); 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; } } 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 #ifdef NRL vty_serv_sock_family (addr, port, AF_INET); vty_serv_sock_family (addr, port, AF_INET6); #else /* ! NRL */ vty_serv_sock_addrinfo (addr, port); #endif /* NRL*/ #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->fd); /* 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); if (vty->buf) XFREE (MTYPE_VTY, vty->buf); /* Check configure. */ vty_config_unlock (vty); /* OK free vty. */ XFREE (MTYPE_VTY, vty); } /* When time out occur output message then close connection. */ static int vty_timeout (struct thread *thread) { struct vty *vty; vty = THREAD_ARG (thread); vty->t_timeout = NULL; vty->v_timeout = 0; /* Clear buffer*/ buffer_reset (vty->obuf); vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); /* Close connection. */ vty->status = VTY_CLOSE; vty_close (vty); return 0; } /* Read up configuration file from file_name. */ static void vty_read_file (FILE *confp) { int ret; struct vty *vty; vty = vty_new (); vty->fd = 0; /* stdout */ vty->type = VTY_TERM; vty->node = CONFIG_NODE; /* Execute configuration file */ ret = config_from_file (vty, confp); if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) { switch (ret) { case CMD_ERR_AMBIGUOUS: fprintf (stderr, "Ambiguous command.\n"); break; case CMD_ERR_NO_MATCH: fprintf (stderr, "There is no such command.\n"); break; } fprintf (stderr, "Error occured during reading below line.\n%s\n", vty->buf); vty_close (vty); exit (1); } vty_close (vty); } 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 (const 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 = (void *)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->fd, 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 *master; static void vty_event (enum event event, int sock, struct vty *vty) { struct thread *vty_serv_thread; switch (event) { case VTY_SERV: vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); break; #ifdef VTYSH case VTYSH_SERV: vty_serv_thread = thread_add_read (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 (master, vtysh_read, vty, sock); break; case VTYSH_WRITE: vty->t_write = thread_add_write (master, vtysh_write, vty, sock); break; #endif /* VTYSH */ case VTY_READ: vty->t_read = thread_add_read (master, vty_read, vty, sock); /* Time out treatment. */ if (vty->v_timeout) { if (vty->t_timeout) thread_cancel (vty->t_timeout); vty->t_timeout = thread_add_timer (master, vty_timeout, vty, vty->v_timeout); } break; case VTY_WRITE: if (! vty->t_write) vty->t_write = thread_add_write (master, vty_flush, vty, sock); break; case VTY_TIMEOUT_RESET: if (vty->t_timeout) { thread_cancel (vty->t_timeout); vty->t_timeout = NULL; } if (vty->v_timeout) { vty->t_timeout = thread_add_timer (master, vty_timeout, vty, vty->v_timeout); } break; } } DEFUN (config_who, config_who_cmd, "who", "Display who is on vty\n") { 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; } /* 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); } 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); master = master_thread; /* 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, &config_who_cmd); install_element (RESTRICTED_NODE, &show_history_cmd); install_element (VIEW_NODE, &config_who_cmd); install_element (VIEW_NODE, &show_history_cmd); install_element (ENABLE_NODE, &config_who_cmd); install_element (CONFIG_NODE, &line_vty_cmd); install_element (CONFIG_NODE, &service_advanced_vty_cmd); install_element (CONFIG_NODE, &no_service_advanced_vty_cmd); install_element (CONFIG_NODE, &show_history_cmd); install_element (ENABLE_NODE, &terminal_monitor_cmd); install_element (ENABLE_NODE, &terminal_no_monitor_cmd); install_element (ENABLE_NODE, &no_terminal_monitor_cmd); install_element (ENABLE_NODE, &show_history_cmd); install_default (VTY_NODE); install_element (VTY_NODE, &exec_timeout_min_cmd); install_element (VTY_NODE, &exec_timeout_sec_cmd); install_element (VTY_NODE, &no_exec_timeout_cmd); install_element (VTY_NODE, &vty_access_class_cmd); install_element (VTY_NODE, &no_vty_access_class_cmd); install_element (VTY_NODE, &vty_login_cmd); install_element (VTY_NODE, &no_vty_login_cmd); 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-0.99.22.4/lib/vty.h0000644000175000017500000002015012177450262011772 00000000000000/* 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_BUFSIZ 512 #define VTY_MAXHIST 20 /* VTY struct. */ struct vty { /* File descripter of this vty. */ int fd; /* Is this vty connect to file or not */ enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type; /* Node status of this vty */ int node; /* 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 supress 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) /* 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 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 (const char *buf, size_t len); #endif /* _ZEBRA_VTY_H */ quagga-0.99.22.4/lib/workqueue.c0000644000175000017500000002264012132522417013171 00000000000000/* * 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; #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; /* 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; } 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%s", ' ', "List","(ms) ","Q. Runs","Cycle Counts ", VTY_NEWLINE); vty_out (vty, "%c %8s %5s %8s %7s %6s %6s %s%s", 'P', "Items", "Hold", "Total", "Best","Gran.","Avg.", "Name", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO ((&work_queues), node, wq)) { vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s", (CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'), listcount (wq->items), wq->spec.hold, wq->runs, wq->cycles.best, wq->cycles.granularity, (wq->runs) ? (unsigned int) (wq->cycles.total / wq->runs) : 0, 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; 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 * * 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) && thread_should_yield (thread)) { yielded = 1; goto stats; } } stats: #define WQ_HYSTERESIS_FACTOR 4 /* we yielded, check whether granularity should be reduced */ if (yielded && (cycles < wq->cycles.granularity)) { wq->cycles.granularity = ((cycles > 0) ? cycles : WORK_QUEUE_MIN_GRANULARITY); } /* otherwise, should granularity increase? */ else if (cycles >= (wq->cycles.granularity)) { if (cycles > wq->cycles.best) wq->cycles.best = cycles; /* 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; } #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-0.99.22.4/lib/workqueue.h0000644000175000017500000001027312132522417013175 00000000000000/* * 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 */ struct { unsigned int best; 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); /* 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-0.99.22.4/lib/zassert.h0000644000175000017500000000125612132522417012642 00000000000000/* * $Id: zassert.h,v 1.2 2004/12/03 18:01:04 ajs Exp $ */ #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-0.99.22.4/lib/zclient.c0000644000175000017500000006733512177450262012633 00000000000000/* 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 *); extern struct thread_master *master; char *zclient_serv_path = NULL; /* This file local debug flag. */ int zclient_debug = 0; /* Allocate zclient structure. */ struct zclient * zclient_new () { 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); 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] = 0; /* Set unwanted redistribute route. bgpd does not need BGP route redistribution. */ zclient->redist_default = redist_default; zclient->redist[redist_default] = 1; /* Set default-information redistribute to zero. */ zclient->default_information = 0; /* Schedule first zclient connection. */ if (zclient_debug) zlog_debug ("zclient start scheduled"); zclient_event (ZCLIENT_SCHEDULE, zclient); } /* Stop zebra client services. */ void zclient_stop (struct zclient *zclient) { 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; } 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) { 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) { 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 ? zclient_serv_path : ZEBRA_SERV_PATH); #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(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(master, zclient->t_write, zclient_flush_data, zclient, zclient->sock); break; } return 0; } void zclient_create_header (struct stream *s, uint16_t command) { /* 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, command); } /* Send simple Zebra message. */ static int zebra_message_send (struct zclient *zclient, int command) { struct stream *s; /* Get zclient output buffer. */ s = zclient->obuf; stream_reset (s); /* Send very simple command only Zebra message. */ zclient_create_header (s, command); 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); zclient_create_header (s, ZEBRA_HELLO); stream_putc (s, zclient->redist_default); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } return 0; } /* Make connection to zebra daemon. */ int zclient_start (struct zclient *zclient) { int i; 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 (zclient_socket_connect(zclient) < 0) { if (zclient_debug) zlog_debug ("zclient connection fail"); zclient->fail++; 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); /* We need router-id information. */ zebra_message_send (zclient, ZEBRA_ROUTER_ID_ADD); /* We need interface information. */ zebra_message_send (zclient, ZEBRA_INTERFACE_ADD); /* Flush all redistribute request. */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, i); /* If default information is needed. */ if (zclient->default_information) zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD); return 0; } /* This function is a wrapper function for calling zclient_start from timer or event thread. */ 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. * * 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); /* 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); /* 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); /* 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); /* 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) { struct stream *s; s = zclient->obuf; stream_reset(s); zclient_create_header (s, command); stream_putc (s, type); stream_putw_at (s, 0, stream_get_endp (s)); return zclient_send_message(zclient); } /* Router-id update from zebra daemon. */ void zebra_router_id_update_read (struct stream *s, struct prefix *rid) { int plen; /* Fetch interface address. */ rid->family = stream_getc (s); plen = prefix_blen (rid); stream_get (&rid->u.prefix, s, plen); rid->prefixlen = stream_getc (s); } /* 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 * +-+-+-+-+-+-+-+-+ * | type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifname | * | | * | | * | | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifindex | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | if_flags | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | metric | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifmtu | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ifmtu6 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | bandwidth | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | sockaddr_dl | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ struct interface * zebra_interface_add_read (struct stream *s) { 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 (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); 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) { 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 (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); /* If such interface does not exist, indicate an error */ if (! ifp) return NULL; zebra_interface_if_set_value (s, ifp); return ifp; } /* * 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.. | * : : * | | * +-+-+-+-+-+-+-+-+ * */ void zebra_interface_if_set_value (struct stream *s, struct interface *ifp) { /* 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); #ifdef HAVE_STRUCT_SOCKADDR_DL stream_get (&ifp->sdl, s, sizeof (ifp->sdl_storage)); #else ifp->hw_addr_len = stream_getl (s); if (ifp->hw_addr_len) stream_get (ifp->hw_addr, s, ifp->hw_addr_len); #endif /* HAVE_STRUCT_SOCKADDR_DL */ } 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) { unsigned int ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; int family; 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 (ifindex); 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. */ family = p.family = stream_getc (s); plen = prefix_blen (&p); stream_get (&p.u.prefix, s, plen); p.prefixlen = stream_getc (s); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); d.family = family; if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* N.B. NULL destination pointers are encoded as all zeroes */ ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ? NULL : &d)); if (ifc != NULL) { ifc->flags = ifc_flags; if (ifc->destination) ifc->destination->prefixlen = ifc->address->prefixlen; } } 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; 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); 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 \n", zclient, command); switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) (*zclient->router_id_update) (command, zclient, length); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) (*zclient->interface_add) (command, zclient, length); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) (*zclient->interface_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) (*zclient->interface_address_add) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) (*zclient->interface_address_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) (*zclient->interface_up) (command, zclient, length); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) (*zclient->interface_down) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) (*zclient->ipv4_route_add) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) (*zclient->ipv4_route_delete) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) (*zclient->ipv6_route_add) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) (*zclient->ipv6_route_delete) (command, zclient, length); 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) { if (command == ZEBRA_REDISTRIBUTE_ADD) { if (zclient->redist[type]) return; zclient->redist[type] = 1; } else { if (!zclient->redist[type]) return; zclient->redist[type] = 0; } if (zclient->sock > 0) zebra_redistribute_send (command, zclient, type); } void zclient_redistribute_default (int command, struct zclient *zclient) { if (command == ZEBRA_REDISTRIBUTE_DEFAULT_ADD) { if (zclient->default_information) return; zclient->default_information = 1; } else { if (!zclient->default_information) return; zclient->default_information = 0; } if (zclient->sock > 0) zebra_message_send (zclient, command); } static void zclient_event (enum event event, struct zclient *zclient) { switch (event) { case ZCLIENT_SCHEDULE: if (! zclient->t_connect) zclient->t_connect = thread_add_event (master, zclient_connect, zclient, 0); break; case ZCLIENT_CONNECT: if (zclient->fail >= 10) return; if (zclient_debug) zlog_debug ("zclient connect schedule interval is %d", zclient->fail < 3 ? 10 : 60); if (! zclient->t_connect) zclient->t_connect = thread_add_timer (master, zclient_connect, zclient, zclient->fail < 3 ? 10 : 60); break; case ZCLIENT_READ: zclient->t_read = thread_add_read (master, zclient_read, zclient, zclient->sock); break; } } 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-0.99.22.4/lib/zclient.h0000644000175000017500000001275712177450262012636 00000000000000/* 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 input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 /* Zebra header size. */ #define ZEBRA_HEADER_SIZE 6 /* Structure for the zebra client. */ struct zclient { /* Socket to zebra daemon. */ int sock; /* Flag of communication to zebra is enabled or not. Default is on. This flag is disabled by `no router zebra' statement. */ int enable; /* Connection failure count. */ int fail; /* Input buffer for zebra message. */ struct stream *ibuf; /* Output buffer for zebra message. */ struct stream *obuf; /* 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; u_char redist[ZEBRA_ROUTE_MAX]; /* Redistribute defauilt. */ u_char default_information; /* Pointer to the callback functions. */ int (*router_id_update) (int, struct zclient *, uint16_t); int (*interface_add) (int, struct zclient *, uint16_t); int (*interface_delete) (int, struct zclient *, uint16_t); int (*interface_up) (int, struct zclient *, uint16_t); int (*interface_down) (int, struct zclient *, uint16_t); int (*interface_address_add) (int, struct zclient *, uint16_t); int (*interface_address_delete) (int, struct zclient *, uint16_t); int (*ipv4_route_add) (int, struct zclient *, uint16_t); int (*ipv4_route_delete) (int, struct zclient *, uint16_t); int (*ipv6_route_add) (int, struct zclient *, uint16_t); int (*ipv6_route_delete) (int, struct zclient *, uint16_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 /* 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 2 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; unsigned int *ifindex; u_char distance; u_int32_t metric; }; /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new (void); 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); /* Send redistribute command to zebra daemon. Do not update zclient state. */ extern int zebra_redistribute_send (int command, struct zclient *, int type); /* If state has changed, update state and call zebra_redistribute_send. */ extern void zclient_redistribute (int command, struct zclient *, int type); /* If state has changed, update state and send the command to zebra. */ extern void zclient_redistribute_default (int command, struct zclient *); /* 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); extern struct interface *zebra_interface_add_read (struct stream *); extern struct interface *zebra_interface_state_read (struct stream *s); extern struct connected *zebra_interface_address_read (int, struct stream *); 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 *); #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; unsigned int *ifindex; u_char distance; u_int32_t metric; }; 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-0.99.22.4/lib/zebra.h0000644000175000017500000004036512211105060012243 00000000000000/* Zebra common header. Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_H #define _ZEBRA_H #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef SUNOS_5 #define _XPG4_2 #define __EXTENSIONS__ typedef unsigned int u_int32_t; typedef unsigned short u_int16_t; typedef unsigned 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 */ #include #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 */ /* 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 */ #ifdef HAVE_LCAPS #include #include #endif /* HAVE_LCAPS */ #ifdef HAVE_SOLARIS_CAPABILITIES #include #endif /* HAVE_SOLARIS_CAPABILITIES */ /* 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 */ /* 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 */ #ifdef BSDI_NRL #ifdef HAVE_NETINET6_IN6_H #include #endif /* HAVE_NETINET6_IN6_H */ #ifdef NRL #include #endif /* NRL */ #define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL #endif /* BSDI_NRL */ /* 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__) \ || (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) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a, 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_MESSAGE_MAX 24 /* 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); /* Zebra's family types. */ #define ZEBRA_FAMILY_IPV4 1 #define ZEBRA_FAMILY_IPV6 2 #define ZEBRA_FAMILY_MAX 3 /* Error codes of zebra. */ #define ZEBRA_ERR_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_CHANGED 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. */ #define AFI_IP 1 #define AFI_IP6 2 #define AFI_MAX 3 /* Subsequent Address Family Identifier. */ #define SAFI_UNICAST 1 #define SAFI_MULTICAST 2 #define SAFI_RESERVED_3 3 #define SAFI_MPLS_VPN 4 #define SAFI_MAX 5 /* Filter direction. */ #define FILTER_IN 0 #define FILTER_OUT 1 #define FILTER_MAX 2 /* Default Administrative Distance of each protocol. */ #define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 #define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 #define ZEBRA_STATIC_DISTANCE_DEFAULT 1 #define ZEBRA_RIP_DISTANCE_DEFAULT 120 #define ZEBRA_RIPNG_DISTANCE_DEFAULT 120 #define ZEBRA_OSPF_DISTANCE_DEFAULT 110 #define ZEBRA_OSPF6_DISTANCE_DEFAULT 110 #define ZEBRA_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) /* AFI and SAFI type. */ typedef u_int16_t afi_t; 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; /* FIFO -- first in first out structure and macros. */ struct fifo { struct fifo *next; struct fifo *prev; }; #define FIFO_INIT(F) \ do { \ struct fifo *Xfifo = (struct fifo *)(F); \ Xfifo->next = Xfifo->prev = Xfifo; \ } while (0) #define FIFO_ADD(F,N) \ do { \ struct fifo *Xfifo = (struct fifo *)(F); \ struct fifo *Xnode = (struct fifo *)(N); \ Xnode->next = Xfifo; \ Xnode->prev = Xfifo->prev; \ Xfifo->prev = Xfifo->prev->next = Xnode; \ } while (0) #define FIFO_DEL(N) \ do { \ struct fifo *Xnode = (struct fifo *)(N); \ Xnode->prev->next = Xnode->next; \ Xnode->next->prev = Xnode->prev; \ } while (0) #define FIFO_HEAD(F) \ ((((struct fifo *)(F))->next == (struct fifo *)(F)) \ ? NULL : (F)->next) #define FIFO_EMPTY(F) \ (((struct fifo *)(F))->next == (struct fifo *)(F)) #define FIFO_TOP(F) \ (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next) #endif /* _ZEBRA_H */ quagga-0.99.22.4/ltmain.sh0000644000175000017500000105152211737722511012061 00000000000000 # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --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 # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed 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) # $progname: (GNU libtool) 2.4.2 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION=2.4.2 TIMESTAMP="" package_revision=1.3337 # 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 # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # 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" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: 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. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # 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" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname 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). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # 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. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # 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 "$removedotparts" -e "$collapseslashes" -e "$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 "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$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_normal_abspath_result=$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_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { 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 "x$func_relative_path_tlibdir" = x ; 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 "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. 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 # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to 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 '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && 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_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_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 "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # 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 () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_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. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent 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 () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent 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 () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi 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 () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # 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. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" 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= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "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 "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; 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 } # 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 # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # 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 if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; 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." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # 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 \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # 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 "$lalib_p" = yes } # 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 () { func_lalib_p "$1" } # 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 () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" 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 () { $opt_debug 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 () { $opt_debug 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 "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; 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 "$lt_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 () { $opt_debug # 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 () { $opt_debug 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 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug $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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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 () { $opt_debug 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_mode_compile arg... func_mode_compile () { $opt_debug # 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 "$build_libtool_libs" != yes && \ func_fatal_configuration "can not 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 "$build_old_libs" = yes; 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 "$pic_mode" = no && test "$deplibs_check_method" != pass_all; 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 "$compiler_c_o" = no; 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 "$need_locks" = yes; 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 "$need_locks" = warn; 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 "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; 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 "$need_locks" = warn && 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 "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; 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 "$need_locks" = warn && 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 "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && 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 -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 () { $opt_debug # 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 test "X$opt_dry_run" = Xfalse; then 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" else # 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 fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug 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_silent && 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 "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # 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=no 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=yes ;; -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$prev" = x-m && 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=yes if test "$isdir" = yes; 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 ;; 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 "$build_old_libs" = yes; 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=yes 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'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; 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_silent || { 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 "$opt_mode" = install && 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 () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; 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$TIMESTAMP) $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 con'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 /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; 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 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[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," 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" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; 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"' # 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_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 () { $opt_debug 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 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 } }'` 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 () { $opt_debug 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 () { $opt_debug 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 which possess that section. Heuristic: eliminate # all those which 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_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 () { $opt_debug 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 () { $opt_debug 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_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 () { $opt_debug 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 () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; 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 "$lock_old_archive_extraction" = yes; 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 () { $opt_debug 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` darwin_base_archive=`basename "$darwin_archive"` 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 "$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 in which 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$TIMESTAMP) $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/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which 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$TIMESTAMP) $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 "$fast_install" = yes; 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 "$shlibpath_overrides_runpath" = yes && 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 /* 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 platforms) ... */ #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 # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #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 ((void *) 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]; int 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 = 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 (strcmp (str, pat) == 0) *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 int 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) { int orig_value_len = strlen (orig_value); int 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 #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\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 () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug 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 # which 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 which 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= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no 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 "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && 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) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; 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 ;; 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 "$pic_object" = none && test "$non_pic_object" = none; 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 "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; 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 "$prev" = dlprefiles; 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 "$non_pic_object" != none; 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 "$pic_object" = none ; 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 ;; 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 "$prev" = rpath; 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$arg" = "X-export-symbols"; 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$arg" = "X-lc" || test "X$arg" = "X-lm"; 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$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && 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$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" 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 ;; -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 # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -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*|-flto*|-fwhopr*|-fuse-linker-plugin) 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 ;; # 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 "$pic_object" = none && test "$non_pic_object" = none; 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 "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; 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 "$prev" = dlprefiles; 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 "$non_pic_object" != none; 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 "$pic_object" = none ; 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 "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; 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 "$export_dynamic" = yes && 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\" 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 "$linkmode" = lib; 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=no 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 "$linkmode,$pass" = "lib,link"; 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 "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; 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 "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; 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 "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # 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 "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; 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=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; 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 "$pass" = conv && 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 "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; 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 "$pass" = link; 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 "$pass" = conv; 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=no 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=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then 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." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; 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=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # 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 "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; 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 "$linkmode" != prog && test "$linkmode" != lib; 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 "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; 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 "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; 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 "X$installed" = Xyes; 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 "X$hardcode_automatic" = Xyes && 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 "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; 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 "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; 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 "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes 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 test "$linkalldeplibs" = yes; 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 "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || 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 test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && 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 "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; 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 "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; 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 "$linkmode" = lib && test "$hardcode_into_libs" = yes; 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*) 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 "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; 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 can not # 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 "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; 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 "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; 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 "$linkmode" = prog; 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 "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; 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 "$linkmode" = prog; 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 "$linkmode" = prog; 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 "$hardcode_direct" != unsupported; 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 "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; 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 can not 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 "$module" = yes; 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 "$build_old_libs" = no; 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 "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; 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 "$link_static" = no && 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 "$link_all_deplibs" != no; 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 "$pass" = link; then if test "$linkmode" = "prog"; 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 "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # 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= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_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 # 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 "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; 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 "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; 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 "$deplibs_check_method" != pass_all; 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 "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; 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 # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|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" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; 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 "$loop" -ne 0; 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 "$loop" -ne 0; 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" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. 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 "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; 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 "X$precious_files_regex" != "X"; 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 "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; 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 "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; 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 "$build_libtool_libs" = yes; 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 "$build_libtool_need_lc" = "yes"; 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 "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; 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 "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; 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 "X$deplibs_check_method" = "Xnone"; 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 "$droppeddeps" = yes; then if test "$module" = yes; 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 "$build_old_libs" = no; 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 "$allow_undefined" = no; 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 "$build_old_libs" = no; 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 "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && 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 "$opt_mode" != relink && 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 if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # 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 fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || 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 "$try_normal_branch" = yes \ && { 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 "X$skipped_export" != "X:"; 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 "X$skipped_export" != "X:" && 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 "$compiler_needs_object" = yes && 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 "$thread_safe" = yes && 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 "$opt_mode" = relink; 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 "$module" = yes && 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 "X$skipped_export" != "X:" && 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 "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; 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 "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; 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 "X$objlist" = X || 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 "$k" -eq 1 ; 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 if ${skipped_export-false}; then 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 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_silent || { 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 "$opt_mode" = relink; 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 if ${skipped_export-false}; then 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 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 "$module" = yes && 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="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { 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 "$opt_mode" = relink; 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 "$opt_mode" = relink; 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 "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; 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= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` 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 "$build_libtool_libs" != yes && 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" ### testsuite: skip nested quoting test 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 if test "$build_libtool_libs" != yes; then 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 fi if test -n "$pic_flag" || test "$pic_mode" != default; 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" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ 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 "$tagname" = CXX ; 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 "$build_old_libs" = yes; 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@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # 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 fi 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 "$no_install" = yes; 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 if test "$hardcode_action" = relink; then # 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" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # 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 if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi 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 "$build_libtool_libs" = yes; 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 "X$oldobjs" = "X" ; 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 "$build_old_libs" = yes && 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 "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; 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 "x$bindir" != x ; 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$TIMESTAMP) $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 can not 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 "$installed" = no && test "$need_relink" = yes; 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 } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= 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=yes ;; -*) 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 "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; 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 test "$rmforce" = yes; 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" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || 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 "$pic_object" != none; 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 "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; 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 "$fast_install" = yes && 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 } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} 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 # in which 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: # vi:sw=2 quagga-0.99.22.4/m4/0000755000175000017500000000000012211704577010633 500000000000000quagga-0.99.22.4/m4/Makefile.am0000644000175000017500000000004212000052240012556 00000000000000EXTRA_DIST=Makefile.am README.txt quagga-0.99.22.4/m4/Makefile.in0000644000175000017500000002663612211704501012620 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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 .PRECIOUS: 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 TAGS: ctags: 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 \ 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 uninstall uninstall-am # 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-0.99.22.4/m4/README.txt0000644000175000017500000000077212000052240012232 00000000000000This 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-0.99.22.4/m4/ax_sys_weak_alias.m40000644000175000017500000002715712177450262014517 00000000000000# =========================================================================== # 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-0.99.22.4/m4/libtool.m40000644000175000017500000106002311737722511012463 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 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) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 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.58])dnl We use AC_INCLUDES_DEFAULT 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_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _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 _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which 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 "X${COLLECT_NAMES+set}" != Xset; 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\\"\\\`\\\\\\"" ;; *) 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\\"\\\`\\\\\\"" ;; *) 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 $lt_write_fail = 0 && 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 "$silent" = yes && 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 which 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 # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $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. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _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 "X${COLLECT_NAMES+set}" != Xset; 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) _LT_PROG_REPLACE_SHELLFNS 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' TIMESTAMP='$TIMESTAMP' 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 $_lt_result -eq 0; 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 $_lt_result -eq 0 && $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 "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; 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 "$lt_cv_ld_force_load" = "no"; 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 "$lt_cv_ld_force_load" = "yes"; 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*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; 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 "$lt_cv_apple_cc_single_mod" != "yes"; 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 "${lt_cv_aix_libpath+set}" = 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 which will find a shell with a builtin # printf (which 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], [ --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 "$GCC" = yes; 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 in which 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 "x$enable_libtool_lock" != xno && 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 which ABI we are using. 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 which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; 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* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. 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*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|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" ;; ppc*-*linux*|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 x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. 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*) 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 "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; 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 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" # 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 x"[$]$2" = xyes; 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 x"[$]$2" = xyes; 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; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # 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"; 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 $i != 17 # 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 "$cross_compiling" = yes; 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 -fvisbility=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 "x$enable_dlopen" != xyes; 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 ]) ;; *) 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 "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && 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 "x$lt_cv_dlopen_self" = xyes; 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 "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; 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 "$hard_links" = no; 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 in which 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 "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # 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 "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; 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 "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; 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_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 AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; 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` 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" else 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 "$host_cpu" = ia64; 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 # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # 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}' else # 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' fi 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%'\''`; test $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 # Handle Gentoo/FreeBSD as it was Linux case $host_vendor in gentoo) version_type=linux ;; *) version_type=freebsd-$objformat ;; esac case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; linux) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' need_lib_prefix=no need_version=no ;; 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 ;; 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' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; 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=yes 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 "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; 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 "$lt_cv_prog_gnu_ld" = yes; 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 ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-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 # Append ld.so.conf contents 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="/lib /usr/lib $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*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac 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 if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; 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 "$with_gnu_ld" = yes; 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=freebsd-elf 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 "$with_gnu_ld" = yes; 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 "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _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], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which 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 which 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 "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; 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 "$with_gnu_ld" = yes; 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 /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 ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; 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) 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*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 ;; 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 case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) 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 "$lt_cv_path_NM" != "no"; 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 /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) 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 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 "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # 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 "$GCC" = yes; 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 "$host_cpu" = ia64; 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 # 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 -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$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 -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/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 # and D for any global 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};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print 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 con'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* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$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 "$pipe_works" = yes; 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_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_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 "$GXX" = yes; 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 "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; 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']) ;; 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 "$host_cpu" = ia64; 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 "$host_cpu" != ia64; 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) 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 "$GCC" = yes; 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 "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; 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']) ;; 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 "$host_cpu" = ia64; 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 ;; 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']) ;; 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) 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' ;; 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 which 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 AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". 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) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | 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 "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) 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 "$with_gnu_ld" = yes; 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 "$lt_use_gnu_ld_interface" = yes; 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 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 "$host_cpu" != ia64; 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 (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; 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 ;; 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 "$host_os" = linux-dietlibc; 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 "$tmp_diet" = no 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' ;; 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 "x$supports_anon_versioning" = xyes; 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 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 "x$supports_anon_versioning" = xyes; 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 can not *** 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 "$_LT_TAGVAR(ld_shlibs, $1)" = no; 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 "$GCC" = yes && 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 "$host_cpu" = ia64; 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 AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". 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) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | 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 # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; 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,' if test "$GCC" = yes; 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 "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; 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 "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi 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_use_runtimelinking" = yes; 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 "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; 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 "$with_gnu_ld" = yes; 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 # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' 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~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $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 "$GCC" = yes; 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 $output_objdir/$soname = $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 $output_objdir/$soname = $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 "$GCC" = yes && test "$with_gnu_ld" = no; 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 "$with_gnu_ld" = no; 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 "$GCC" = yes && test "$with_gnu_ld" = no; 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 "$with_gnu_ld" = no; 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 "$GCC" = yes; 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 "$lt_cv_irix_exported_symbol" = yes; 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 ;; 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*) 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__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _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' ;; esac 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 _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; 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 "$GCC" = yes; 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 "$GCC" = yes; 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 "$GCC" = yes; 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 "x$host_vendor" = xsequent; 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 "$GCC" = yes; 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 can NOT 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 "$GCC" = yes; 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 x$host_vendor = xsni; 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 "$_LT_TAGVAR(ld_shlibs, $1)" = no && 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 "$enable_shared" = yes && test "$GCC" = yes; 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 which 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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 "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; 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 "$_lt_caught_CXX_error" != yes; 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 "$GXX" = yes; 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 "$GXX" = yes; 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 "$with_gnu_ld" = yes; 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 "$host_cpu" = ia64; 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 # need to do runtime linking. 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 ;; 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,' if test "$GXX" = yes; 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 "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; 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 "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi 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_use_runtimelinking" = yes; 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 "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; 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 "$with_gnu_ld" = yes; 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 # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' 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~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $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 (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; 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) ;; 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 ;; gnu*) ;; 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 $output_objdir/$soname = $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 "$GXX" = yes; 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 $output_objdir/$soname = $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 $with_gnu_ld = no; 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 "$GXX" = yes; then if test $with_gnu_ld = no; 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 "$GXX" = yes; then if test "$with_gnu_ld" = no; 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) 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 "x$supports_anon_versioning" = xyes; 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 ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) 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__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 "$GXX" = yes && test "$with_gnu_ld" = no; 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 "$GXX" = yes && test "$with_gnu_ld" = no; 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 $LDFLAGS $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 -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 $LDFLAGS $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 -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 can NOT 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 "$_LT_TAGVAR(ld_shlibs, $1)" = no && 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 "$_lt_caught_CXX_error" != yes 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 ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; 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 $p = "-L" || test $p = "-R"; 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 "$pre_test_object_deps_done" = no; 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 "$pre_test_object_deps_done" = no; 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)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; 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 "X$F77" = "Xno"; 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 "$_lt_disable_F77" != yes; 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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 "$_lt_disable_F77" != yes 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 "X$FC" = "Xno"; 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 "$_lt_disable_FC" != yes; 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 "$can_build_shared" = "no" && 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 "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no 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 "$enable_shared" = yes || 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 "$_lt_disable_FC" != yes 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 "x${GCJFLAGS+set}" = xset || 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 $lt_ac_count -gt 10 && 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], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) 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_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which 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-0.99.22.4/m4/ltoptions.m40000644000175000017500000003007311737722511013053 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 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 7 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_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_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=default]) test -z "$pic_mode" && 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-0.99.22.4/m4/ltsugar.m40000644000175000017500000001042411737722511012477 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 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-0.99.22.4/m4/ltversion.m40000644000175000017500000000126211737722511013043 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 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 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) quagga-0.99.22.4/m4/lt~obsolete.m40000644000175000017500000001375611737722511013403 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 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-0.99.22.4/missing0000755000175000017500000002370312070614057011633 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.18; # UTC # Copyright (C) 1996-2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, 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 run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, 'missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle 'PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file 'aclocal.m4' autoconf touch file 'configure' autoheader touch file 'config.h.in' autom4te touch the output file, or create a stub one automake touch all 'Makefile.in' files bison create 'y.tab.[ch]', if possible, from existing .[ch] flex create 'lex.yy.c', if possible, from existing .c help2man touch the output file lex create 'lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create 'y.tab.[ch]', if possible, from existing .[ch] 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 # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running '$TOOL --version' or '$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified 'acinclude.m4' or '${configure_ac}'. You might want to install the Automake and Perl packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified '${configure_ac}'. You might want to install the Autoconf and GNU m4 packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified 'acconfig.h' or '${configure_ac}'. You might want to install the Autoconf and GNU m4 packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified 'Makefile.am', 'acinclude.m4' or '${configure_ac}'. You might want to install the Automake and Perl packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: '$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get '$1' as part of Autoconf from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: '$1' $msg. You should only need it if you modified a '.y' file. You may need the Bison package in order for those modifications to take effect. You can get Bison from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified a '.l' file. You may need the Flex package in order for those modifications to take effect. You can get Flex from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the Help2man package in order for those modifications to take effect. You can get Help2man from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: '$1' is $msg. You should only need it if you modified a '.texi' or '.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy 'make' (AIX, DU, IRIX). You might want to install the Texinfo package or the GNU make package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: '$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the 'README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing '$1' program." exit 1 ;; esac exit 0 # 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-0.99.22.4/ospf6d/0000755000175000017500000000000012211704577011514 500000000000000quagga-0.99.22.4/ospf6d/Makefile.am0000644000175000017500000000204212177450262013466 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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-0.99.22.4/ospf6d/Makefile.in0000644000175000017500000005764412211704501013504 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = README $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru 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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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 .PRECIOUS: 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) -rm -f libospf6.a $(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD) $(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) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/ospf6d/README0000644000175000017500000000515012000052240012270 00000000000000 Zebra OSPF daemon for IPv6 network 2003/08/18 README for newer code is not yet. General usage should remain the same. For further usage, see command helps by typing '?' in vty, and then imagin ! ;p) Previous README contents follows. Zebra OSPF daemon for IPv6 network 2001/12/20 Zebra OSPF6d is OSPF version 3 daemon which is specified by "OSPF for IPv6" (RFC 2740). *** NOTE *** Zebra ospf6d is in development yet. It may lack some functionalities, and may have some bugs. Use the latest version from the anoncvs repository (http://www.zebra.org/cvs.html) ! This file README is like memo yet, so please feel free to ask by E-mail. Patches will be appriciated. ospf6d's vty port was default to 2606/tcp. Use commands below. VIEW NODE: show ipv6 ospf6 To see Router-ID, uptime of ospf6d, some statistics. show ipv6 ospf6 database ... This command shows LSA database. You can specify LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized. show ipv6 ospf6 interface ... To see the status of the OSPF interface, and the configuration like interface costs. show ipv6 ospf6 neighbor ... Shows state of neighbors and choosed (Backup) DR on the I/F. show ipv6 ospf6 route (X::X) This command shows internal routing table of the ospf6d. Routes not calculated by OSPFv3 (like connected routes) are not shown. If Address is specified (X::X), shows the route that the address matches. show ipv6 ospf6 route redistribute (X::X) Shows the routes advertised as AS-External routes by the router itself. If Address is specified (X::X), shows the route that the address matches. CONFIG NODE: interface NAME To enter INTERFACE NODE router ospf6 ... To enter OSPF6 NODE INTERFACE NODE: ipv6 ospf6 cost COST Sets the interface's output cost. default 1 ipv6 ospf6 hello-interval HELLOINTERVAL Sets the interface's Hello Interval. default 10 ipv6 ospf6 dead-interval DEADINTERVAL Sets the interface's Router Dead Interval. default 40 ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL Sets the interface's Rxmt Interval. default 5 ipv6 ospf6 priority PRIORITY Sets the interface's Router Priority. default 1 ipv6 ospf6 transmit-delay TRANSMITDELAY Sets the interface's Inf-Trans-Delay. default 1 OSPF6 NODE: router-id A.B.C.D Sets the router's Router-ID interface NAME area AREA Binds interface to specified Area, and start sending OSPFv3 packets. Sample configuration is in ospf6d.conf.sample. -- Yasuhiro Ohara Kunihiro Ishiguro quagga-0.99.22.4/ospf6d/ospf6_abr.c0000644000175000017500000006411512132522417013461 00000000000000/* * 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; struct ospf6_lsa *old; struct listnode *node, *nnode; /* Withdraw all summary prefixes previously originated */ for (ro = ospf6_route_head (area->summary_prefix); ro; ro = ospf6_route_next (ro)) { old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) ospf6_lsa_purge (old); ospf6_route_remove (ro, area->summary_prefix); } /* Withdraw all summary router-routes previously originated */ for (ro = ospf6_route_head (area->summary_router); ro; ro = ospf6_route_next (ro)) { old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) ospf6_lsa_purge (old); ospf6_route_remove (ro, area->summary_router); } /* Schedule Router-LSA for each area (ABR status may change) */ for (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 >= 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 != BACKBONE_AREA_ID || ! 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; memset (&prefix, 0, sizeof (prefix)); if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { struct ospf6_inter_prefix_lsa *prefix_lsa; if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) { is_debug++; zlog_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)) { struct ospf6_inter_router_lsa *router_lsa; 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 == 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 */ 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; } } /* (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 int ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_prefix_lsa *prefix_lsa; struct in6_addr in6; char buf[64]; prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (prefix_lsa), VNL); ospf6_prefix_options_printbuf (prefix_lsa->prefix.prefix_options, buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); vty_out (vty, " Prefix: %s/%d%s", buf, prefix_lsa->prefix.prefix_length, VNL); return 0; } 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", ospf6_inter_area_prefix_lsa_show }; struct ospf6_lsa_handler inter_router_handler = { OSPF6_LSTYPE_INTER_ROUTER, "Inter-Router", ospf6_inter_area_router_lsa_show }; void ospf6_abr_init (void) { ospf6_install_lsa_handler (&inter_prefix_handler); ospf6_install_lsa_handler (&inter_router_handler); } quagga-0.99.22.4/ospf6d/ospf6_abr.h0000644000175000017500000000477012045513244013470 00000000000000/* * 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" /* 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-0.99.22.4/ospf6d/ospf6_area.c0000644000175000017500000005142612045513244013627 00000000000000/* * 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_AREA (lsa->lsdb->data)); break; case OSPF6_LSTYPE_INTRA_PREFIX: ospf6_intra_prefix_lsa_add (lsa); break; case OSPF6_LSTYPE_INTER_PREFIX: case OSPF6_LSTYPE_INTER_ROUTER: ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data); break; default: break; } } 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_AREA (lsa->lsdb->data)); break; case OSPF6_LSTYPE_INTRA_PREFIX: ospf6_intra_prefix_lsa_remove (lsa); break; case OSPF6_LSTYPE_INTER_PREFIX: case OSPF6_LSTYPE_INTER_ROUTER: ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data); break; default: break; } } 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 */ OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); OSPF6_OPT_SET (oa->options, OSPF6_OPT_E); OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); oa->ospf6 = o; listnode_add_sort (o->area_list, oa); /* import athoer area's routes as inter-area routes */ for (route = ospf6_route_head (o->route_table); route; route = ospf6_route_next (route)) ospf6_abr_originate_summary_to_area (route, oa); return oa; } void ospf6_area_delete (struct ospf6_area *oa) { struct listnode *n, *nnode; struct ospf6_interface *oi; ospf6_route_table_delete (oa->range_table); ospf6_route_table_delete (oa->summary_prefix); ospf6_route_table_delete (oa->summary_router); /* ospf6 interface list */ for (ALL_LIST_ELEMENTS (oa->if_list, n, nnode, oi)) { ospf6_interface_delete (oi); } 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); } 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); } 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; 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) { 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 caculation\n" "Show SPF tree\n") { struct listnode *node; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); for (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 caculation\n" "Show SPF tree\n") { u_int32_t area_id; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); if (inet_pton (AF_INET, argv[0], &area_id) != 1) { vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VNL); return CMD_SUCCESS; } oa = ospf6_area_lookup (area_id, ospf6); if (oa == NULL) { vty_out (vty, "No such Area: %s%s", argv[0], VNL); return CMD_SUCCESS; } route = ospf6_route_lookup (&prefix, oa->spf_table); if (route == NULL) { vty_out (vty, "LS entry for root not found in area %s%s", oa->name, VNL); return CMD_SUCCESS; } root = (struct ospf6_vertex *) route->route_option; ospf6_spf_display_subtree (vty, "", 0, root); return CMD_SUCCESS; } DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, show_ipv6_ospf6_simulate_spf_tree_root_cmd, "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D", SHOW_STR IP6_STR OSPF6_STR "Shortest Path First caculation\n" "Show SPF tree\n" "Specify root's router-id to calculate another router's SPF tree\n") { u_int32_t area_id; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; u_int32_t router_id; struct ospf6_route_table *spf_table; unsigned char tmp_debug_ospf6_spf = 0; inet_pton (AF_INET, argv[0], &router_id); ospf6_linkstate_prefix (router_id, htonl (0), &prefix); if (inet_pton (AF_INET, argv[1], &area_id) != 1) { vty_out (vty, "Malformed Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } oa = ospf6_area_lookup (area_id, ospf6); if (oa == NULL) { vty_out (vty, "No such Area: %s%s", argv[1], VNL); return CMD_SUCCESS; } tmp_debug_ospf6_spf = conf_debug_ospf6_spf; conf_debug_ospf6_spf = 0; spf_table = OSPF6_ROUTE_TABLE_CREATE (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 (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); install_element (OSPF6_NODE, &area_range_cmd); install_element (OSPF6_NODE, &area_range_advertise_cmd); install_element (OSPF6_NODE, &no_area_range_cmd); install_element (OSPF6_NODE, &area_import_list_cmd); install_element (OSPF6_NODE, &no_area_import_list_cmd); install_element (OSPF6_NODE, &area_export_list_cmd); install_element (OSPF6_NODE, &no_area_export_list_cmd); install_element (OSPF6_NODE, &area_filter_list_cmd); install_element (OSPF6_NODE, &no_area_filter_list_cmd); } quagga-0.99.22.4/ospf6d/ospf6_area.h0000644000175000017500000000704412177450262013637 00000000000000/* * 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 BACKBONE_AREA_ID (htonl (0)) #define IS_AREA_BACKBONE(oa) ((oa)->area_id == BACKBONE_AREA_ID) #define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE)) #define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE)) #define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT)) #define IS_AREA_STUB(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_STUB)) /* prototypes */ 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-0.99.22.4/ospf6d/ospf6_asbr.c0000644000175000017500000011031512132522417013636 00000000000000/* * 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 *old, *lsa; struct ospf6_external_info *info = route->route_option; struct ospf6_as_external_lsa *as_external_lsa; char buf[64]; caddr_t p; /* find previous LSA */ old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), route->path.origin.id, ospf6->router_id, ospf6->lsdb); if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_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 */ 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)) { /* xxx */ } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_AS_EXTERNAL); lsa_header->id = route->path.origin.id; lsa_header->adv_router = ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, ospf6->lsdb); lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_process (lsa, ospf6); } void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix asbr_id; struct ospf6_route *asbr_entry, *route; char buf[64]; int i; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_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) == LS_INFINITY) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with LSInfinity Metric"); return; } ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id); asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table); if (asbr_entry == NULL || ! CHECK_FLAG (asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&asbr_id, buf, sizeof (buf)); zlog_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; } 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; 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 = 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); } } 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); } } void ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop) { int ret; struct ospf6_route troute; struct ospf6_external_info tinfo; struct ospf6_route *route, *match; struct ospf6_external_info *info; struct prefix prefix_id; struct route_node *node; char pbuf[64], ibuf[16]; 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; 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->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->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, int ifindex, struct prefix *prefix) { struct ospf6_route *match; struct ospf6_external_info *info = NULL; struct route_node *node; struct ospf6_lsa *lsa; struct prefix prefix_id; char pbuf[64], ibuf[16]; 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_routemap_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); ospf6_asbr_routemap_unset (type); return CMD_SUCCESS; } int ospf6_redistribute_config_write (struct vty *vty) { int type; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (type == ZEBRA_ROUTE_OSPF6) continue; if (! ospf6_zebra_is_redistribute (type)) continue; if (ospf6->rmap[type].name) vty_out (vty, " redistribute %s route-map %s%s", ZROUTE_NAME (type), ospf6->rmap[type].name, VNL); else vty_out (vty, " redistribute %s%s", ZROUTE_NAME (type), VNL); } return 0; } 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 }; 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 > 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 int route_map_command_status (struct vty *vty, int ret) { if (! ret) return CMD_SUCCESS; switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "Can't find rule.%s", VNL); break; case RMAP_COMPILE_ERROR: vty_out (vty, "Argument is malformed.%s", VNL); break; default: vty_out (vty, "route-map add set failed.%s", VNL); break; } return CMD_WARNING; } /* add "match address" */ DEFUN (ospf6_routemap_match_address_prefixlist, ospf6_routemap_match_address_prefixlist_cmd, "match ipv6 address prefix-list WORD", "Match values\n" IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") { int ret = route_map_add_match ((struct route_map_index *) vty->index, "ipv6 address prefix-list", argv[0]); return route_map_command_status (vty, ret); } /* delete "match address" */ DEFUN (ospf6_routemap_no_match_address_prefixlist, ospf6_routemap_no_match_address_prefixlist_cmd, "no match ipv6 address prefix-list WORD", NO_STR "Match values\n" IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, "ipv6 address prefix-list", argv[0]); return route_map_command_status (vty, ret); } /* "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", MATCH_STR NO_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", MATCH_STR NO_STR "Match first hop interface of route\n" "Interface name\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 <0-4294967295>", NO_STR "Set value\n" "Metric\n" "METRIC value\n") { int ret = route_map_delete_set ((struct route_map_index *) vty->index, "metric", argv[0]); return route_map_command_status (vty, ret); } /* add "set forwarding-address" */ DEFUN (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd, "set forwarding-address X:X::X:X", "Set value\n" "Forwarding Address\n" "IPv6 Address\n") { int ret = route_map_add_set ((struct route_map_index *) vty->index, "forwarding-address", argv[0]); return route_map_command_status (vty, ret); } /* delete "set forwarding-address" */ DEFUN (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd, "no set forwarding-address X:X::X:X", NO_STR "Set value\n" "Forwarding Address\n" "IPv6 Address\n") { int ret = route_map_delete_set ((struct route_map_index *) vty->index, "forwarding-address", argv[0]); return route_map_command_status (vty, ret); } 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_set (&ospf6_routemap_rule_set_metric_type_cmd); route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); /* Match address prefix-list */ install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd); /* 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); /* ASE Metric Type (e.g. Type-1/Type-2) */ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); /* ASE Metric */ install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); /* ASE Metric */ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); } /* Display functions */ static int ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; char buf[64]; struct in6_addr in6, *forwarding; assert (lsa->header); external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); /* bits */ snprintf (buf, sizeof (buf), "%c%c%c", (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E' : '-'), (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F' : '-'), (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T' : '-')); vty_out (vty, " Bits: %s%s", buf, VNL); vty_out (vty, " Metric: %5lu%s", (u_long) OSPF6_ASBR_METRIC (external), VNL); ospf6_prefix_options_printbuf (external->prefix.prefix_options, buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); vty_out (vty, " Referenced LSType: %d%s", ntohs (external->prefix.prefix_refer_lstype), VNL); ospf6_prefix_in6_addr (&in6, &external->prefix); inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); vty_out (vty, " Prefix: %s/%d%s", buf, external->prefix.prefix_length, VNL); /* Forwarding-Address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { forwarding = (struct in6_addr *) ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + OSPF6_PREFIX_SPACE (external->prefix.prefix_length)); inet_ntop (AF_INET6, forwarding, buf, sizeof (buf)); vty_out (vty, " Forwarding-Address: %s%s", buf, VNL); } return 0; } 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_redistribute_show_config (vty); for (route = ospf6_route_head (ospf6->external_table); route; route = ospf6_route_next (route)) ospf6_asbr_external_route_show (vty, route); return CMD_SUCCESS; } struct ospf6_lsa_handler as_external_handler = { OSPF6_LSTYPE_AS_EXTERNAL, "AS-External", ospf6_as_external_lsa_show }; void ospf6_asbr_init (void) { ospf6_routemap_init (); ospf6_install_lsa_handler (&as_external_handler); install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); } 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-0.99.22.4/ospf6d/ospf6_asbr.h0000644000175000017500000000606712132522417013653 00000000000000/* * 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; /* u_int32_t tag; */ unsigned int 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, int ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop); extern void ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix); extern int ospf6_redistribute_config_write (struct vty *vty); extern void ospf6_asbr_init (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-0.99.22.4/ospf6d/ospf6_flood.c0000644000175000017500000007372412177450262014035 00000000000000/* * 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, 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); } if (old) ospf6_flood_clear (old); ospf6_flood (NULL, lsa); ospf6_install_lsa (lsa); } void ospf6_lsa_originate_process (struct ospf6_lsa *lsa, struct ospf6 *process) { lsa->lsdb = process->lsdb; ospf6_lsa_originate (lsa); } void ospf6_lsa_originate_area (struct ospf6_lsa *lsa, struct ospf6_area *oa) { lsa->lsdb = oa->lsdb; ospf6_lsa_originate (lsa); } void ospf6_lsa_originate_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi) { lsa->lsdb = oi->lsdb; ospf6_lsa_originate (lsa); } void ospf6_lsa_purge (struct ospf6_lsa *lsa) { struct ospf6_lsa *self; struct ospf6_lsdb *lsdb_self; /* remove it from the LSDB for self-originated LSAs */ lsdb_self = ospf6_get_scoped_lsdb_self (lsa); self = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb_self); if (self) { THREAD_OFF (self->expire); THREAD_OFF (self->refresh); ospf6_lsdb_remove (self, lsdb_self); } ospf6_lsa_premature_aging (lsa); } void ospf6_increment_retrans_count (struct ospf6_lsa *lsa) { /* The LSA must be the original one (see the description in ospf6_decrement_retrans_count () below) */ lsa->retrans_count++; } void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa) { struct ospf6_lsdb *lsdb; struct ospf6_lsa *orig; /* The LSA must be on the retrans-list of a neighbor. It means the "lsa" is a copied one, and we have to decrement the retransmission count of the original one (instead of this "lsa"'s). In order to find the original LSA, first we have to find appropriate LSDB that have the original LSA. */ lsdb = ospf6_get_scoped_lsdb (lsa); /* Find the original LSA of which the retrans_count should be decremented */ orig = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb); if (orig) { orig->retrans_count--; assert (orig->retrans_count >= 0); } } /* RFC2328 section 13.2 Installing LSAs in the database */ void ospf6_install_lsa (struct ospf6_lsa *lsa) { struct ospf6_lsa *old; struct timeval now; if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) zlog_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); 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, MAXAGE + lsa->birth.tv_sec - now.tv_sec); else lsa->expire = NULL; /* actually install */ lsa->installed = now; ospf6_lsdb_add (lsa, lsa->lsdb); return; } /* RFC2740 section 3.5.2. Sending Link State Update packets */ /* RFC2328 section 13.3 Next step in the flooding procedure */ 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 newer, next neighbor"); continue; } /* If the same instance, delete from request-list and examin next neighbor */ if (ospf6_lsa_compare (lsa, req) == 0) { if (is_debug) zlog_debug ("Requesting the same, remove it, next neighbor"); ospf6_lsdb_remove (req, on->request_list); continue; } /* If the new LSA is more recent, delete from request-list */ if (ospf6_lsa_compare (lsa, req) < 0) { if (is_debug) zlog_debug ("Received is newer, remove requesting"); ospf6_lsdb_remove (req, on->request_list); /* fall through */ } } } /* (c) If the new LSA was received from this neighbor, examin next neighbor */ if (from == on) { if (is_debug) zlog_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 && oi->state == OSPF6_INTERFACE_BDR) { if (is_debug) zlog_debug ("Received is from the I/F, itself BDR, next interface"); return; } /* (5) flood the LSA out the interface. */ if (is_debug) zlog_debug ("Schedule flooding for the interface"); if (if_is_broadcast (oi->interface)) { ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list); if (oi->thread_send_lsupdate == NULL) oi->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); } else { /* reschedule retransmissions to all neighbors */ for (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 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 (BDR & FloodBack)"); return; } /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgement sent if advertisement received from Designated Router, otherwide do nothing. */ if (ismore_recent < 0) { if (oi->drouter == from->router_id) { if (is_debug) zlog_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 < MIN_LS_ARRIVAL) { 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 ("Flood, Install, Possibly acknowledge the received LSA"); /* (b) immediately flood and (c) remove from all retrans-list */ /* Prevent self-originated LSA to be flooded. this is to make reoriginated instance of the LSA not to be rejected by other routers due to MinLSArrival. */ if (new->header->adv_router != from->ospf6_if->area->ospf6->router_id) ospf6_flood (from, new); /* (c) Remove the current database copy from all neighbors' Link state retransmission lists. */ /* XXX, flood_clear ? */ /* (d), installing lsdb, which may cause routing table calculation (replacing database copy) */ ospf6_install_lsa (new); /* (e) possibly acknowledge */ ospf6_acknowledge_lsa (new, ismore_recent, from); /* (f) Self Originated LSA, section 13.4 */ if (new->header->adv_router == from->ospf6_if->area->ospf6->router_id) { /* Self-originated LSA (newer than ours) is received from another router. We have to make a new instance of the LSA or have to flush this LSA. */ if (is_debug) { zlog_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 (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-0.99.22.4/ospf6d/ospf6_flood.h0000644000175000017500000000472612000052240014011 00000000000000/* * 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-0.99.22.4/ospf6d/ospf6_interface.c0000644000175000017500000012737412177450262014673 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "memory.h" #include "if.h" #include "log.h" #include "command.h" #include "thread.h" #include "prefix.h" #include "plist.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_network.h" #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_spf.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_interface = 0; const char *ospf6_interface_state_str[] = { "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL }; struct ospf6_interface * ospf6_interface_lookup_by_ifindex (int ifindex) { struct ospf6_interface *oi; struct interface *ifp; ifp = if_lookup_by_index (ifindex); if (ifp == NULL) return (struct ospf6_interface *) NULL; oi = (struct ospf6_interface *) ifp->info; return oi; } /* schedule routing table recalculation */ static void ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa) { switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_LINK: if (OSPF6_INTERFACE (lsa->lsdb->data)->state == OSPF6_INTERFACE_DR) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (OSPF6_INTERFACE (lsa->lsdb->data)); ospf6_spf_schedule (OSPF6_INTERFACE (lsa->lsdb->data)->area); break; default: break; } } /* Create new ospf6 interface structure */ struct ospf6_interface * ospf6_interface_create (struct interface *ifp) { struct ospf6_interface *oi; 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 = OSPF6_INTERFACE_HELLO_INTERVAL; oi->dead_interval = OSPF6_INTERFACE_DEAD_INTERVAL; oi->rxmt_interval = OSPF6_INTERFACE_RXMT_INTERVAL; oi->cost = OSPF6_INTERFACE_COST; 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; oi->lsdb->hook_remove = ospf6_interface_lsdb_hook; 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; 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); oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0); } void ospf6_interface_disable (struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete (on); list_delete_all_node (oi->neighbor_list); ospf6_lsdb_remove_all (oi->lsdb); ospf6_lsdb_remove_all (oi->lsupdate_list); ospf6_lsdb_remove_all (oi->lsack_list); THREAD_OFF (oi->thread_send_hello); THREAD_OFF (oi->thread_send_lsupdate); THREAD_OFF (oi->thread_send_lsack); } static struct in6_addr * ospf6_interface_get_linklocal_address (struct interface *ifp) { 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 */ if (oi->area) thread_add_event (master, interface_up, oi, 0); } void ospf6_interface_if_del (struct interface *ifp) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* interface stop */ if (oi->area) thread_execute (master, interface_down, oi, 0); listnode_delete (oi->area->if_list, oi); oi->area = (struct ospf6_area *) NULL; /* cut link */ oi->interface = NULL; ifp->info = NULL; ospf6_interface_delete (oi); } void ospf6_interface_state_update (struct interface *ifp) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; if (oi->area == NULL) return; if (if_is_up (ifp)) thread_add_event (master, interface_up, oi, 0); else thread_add_event (master, interface_down, oi, 0); return; } void ospf6_interface_connected_route_update (struct interface *ifp) { struct ospf6_interface *oi; struct ospf6_route *route; struct connected *c; 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; /* 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_up (oi->interface)) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s is down, can't execute [InterfaceUp]", oi->interface->name); return 0; } /* if already enabled, do nothing */ if (oi->state > OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s already enabled", oi->interface->name); return 0; } /* Join AllSPFRouters */ ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP); /* Update interface route */ ospf6_interface_connected_route_update (oi->interface); /* Schedule Hello */ if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) thread_add_event (master, ospf6_hello_send, oi, 0); /* decide next interface state */ if (if_is_pointopoint (oi->interface)) ospf6_interface_state_change (OSPF6_INTERFACE_POINTTOPOINT, oi); else if (oi->priority == 0) ospf6_interface_state_change (OSPF6_INTERFACE_DROTHER, oi); else { ospf6_interface_state_change (OSPF6_INTERFACE_WAITING, oi); thread_add_timer (master, wait_timer, oi, oi->dead_interval); } return 0; } int wait_timer (struct thread *thread) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_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); /* 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); 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_up (ifp)], type, VNL); vty_out (vty, " Interface ID: %d%s", ifp->ifindex, VNL); if (ifp->info == NULL) { vty_out (vty, " OSPF not enabled on this interface%s", VNL); return 0; } else oi = (struct ospf6_interface *) ifp->info; vty_out (vty, " Internet Address:%s", VNL); for (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 %hu%s", strbuf, oi->cost, VNL); } else vty_out (vty, " Not Attached to Area%s", VNL); vty_out (vty, " State %s, Transmit Delay %d sec, Priority %d%s", ospf6_interface_state_str[oi->state], oi->transdelay, oi->priority, VNL); vty_out (vty, " Timer intervals configured:%s", VNL); vty_out (vty, " Hello %d, Dead %d, Retransmit %d%s", oi->hello_interval, oi->dead_interval, oi->rxmt_interval, VNL); inet_ntop (AF_INET, &oi->drouter, drouter, sizeof (drouter)); inet_ntop (AF_INET, &oi->bdrouter, bdrouter, sizeof (bdrouter)); vty_out (vty, " DR: %s BDR: %s%s", drouter, bdrouter, VNL); vty_out (vty, " Number of I/F scoped LSAs is %u%s", oi->lsdb->count, VNL); 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; /* update cost held in route_connected list in ospf6_interface */ ospf6_interface_connected_route_update (oi->interface); /* execute LSA hooks */ if (oi->area) { OSPF6_LINK_LSA_SCHEDULE (oi); OSPF6_ROUTER_LSA_SCHEDULE (oi->area); OSPF6_NETWORK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } return CMD_SUCCESS; } DEFUN (ipv6_ospf6_hellointerval, ipv6_ospf6_hellointerval_cmd, "ipv6 ospf6 hello-interval <1-65535>", IP6_STR OSPF6_STR "Interval time of Hello packets\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->hello_interval = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_deadinterval, ipv6_ospf6_deadinterval_cmd, "ipv6 ospf6 dead-interval <1-65535>", IP6_STR OSPF6_STR "Interval time after which a neighbor is declared down\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->dead_interval = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_transmitdelay, ipv6_ospf6_transmitdelay_cmd, "ipv6 ospf6 transmit-delay <1-3600>", IP6_STR OSPF6_STR "Transmit delay of this interface\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->transdelay = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_retransmitinterval, ipv6_ospf6_retransmitinterval_cmd, "ipv6 ospf6 retransmit-interval <1-65535>", IP6_STR OSPF6_STR "Time between retransmitting lost link state advertisements\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->rxmt_interval = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_priority, ipv6_ospf6_priority_cmd, "ipv6 ospf6 priority <0-255>", IP6_STR OSPF6_STR "Router priority\n" "Priority value\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->priority = strtol (argv[0], NULL, 10); if (oi->area) ospf6_interface_state_change (dr_election (oi), oi); return CMD_SUCCESS; } DEFUN (ipv6_ospf6_instance, ipv6_ospf6_instance_cmd, "ipv6 ospf6 instance-id <0-255>", IP6_STR OSPF6_STR "Instance ID for this interface\n" "Instance ID value\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *)vty->index; assert (ifp); oi = (struct ospf6_interface *)ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->instance_id = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } DEFUN (ipv6_ospf6_passive, ipv6_ospf6_passive_cmd, "ipv6 ospf6 passive", IP6_STR OSPF6_STR "passive interface, No adjacency will be formed on this interface\n" ) { struct ospf6_interface *oi; struct interface *ifp; 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; } 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 (oi->cost != OSPF6_INTERFACE_COST) 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); 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 (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); install_element (CONFIG_NODE, &interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_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); } 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-0.99.22.4/ospf6d/ospf6_interface.h0000644000175000017500000001074612177450262014672 00000000000000/* * 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; /* 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; /* 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 /* 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 /* 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_if_del (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 int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); #endif /* OSPF6_INTERFACE_H */ quagga-0.99.22.4/ospf6d/ospf6_intra.c0000644000175000017500000014351112132522417014030 00000000000000/* * 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" 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 int ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char *start, *end, *current; char buf[32], name[32], bits[16], options[32]; struct ospf6_router_lsa *router_lsa; struct ospf6_router_lsdesc *lsdesc; router_lsa = (struct ospf6_router_lsa *) ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); ospf6_capability_printbuf (router_lsa->bits, bits, sizeof (bits)); ospf6_options_printbuf (router_lsa->options, options, sizeof (options)); vty_out (vty, " Bits: %s Options: %s%s", bits, options, VNL); start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); for (current = start; current + sizeof (struct ospf6_router_lsdesc) <= end; current += sizeof (struct ospf6_router_lsdesc)) { lsdesc = (struct ospf6_router_lsdesc *) current; if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT) snprintf (name, sizeof (name), "Point-To-Point"); else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK) snprintf (name, sizeof (name), "Transit-Network"); else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK) snprintf (name, sizeof (name), "Stub-Network"); else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK) snprintf (name, sizeof (name), "Virtual-Link"); else snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type); vty_out (vty, " Type: %s Metric: %d%s", name, ntohs (lsdesc->metric), VNL); vty_out (vty, " Interface ID: %s%s", inet_ntop (AF_INET, &lsdesc->interface_id, buf, sizeof (buf)), VNL); vty_out (vty, " Neighbor Interface ID: %s%s", inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, buf, sizeof (buf)), VNL); vty_out (vty, " Neighbor Router ID: %s%s", inet_ntop (AF_INET, &lsdesc->neighbor_router_id, buf, sizeof (buf)), VNL); } return 0; } int ospf6_router_lsa_originate (struct thread *thread) { struct ospf6_area *oa; char buffer [OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *lsa; u_int32_t link_state_id = 0; 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) && ((caddr_t) lsdesc + sizeof (struct ospf6_router_lsdesc) - /* XXX warning: comparison between signed and unsigned */ (caddr_t) buffer > oa->router_lsa_size_limit)) { if ((caddr_t) lsdesc == (caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)) { if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) zlog_debug ("Size limit setting for Router-LSA too short"); return 0; } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); lsa_header->id = htonl (link_state_id); lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oa); /* Reset setting for consecutive origination */ memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa), 0, (caddr_t) lsdesc - (caddr_t) router_lsa); lsdesc = (struct ospf6_router_lsdesc *) ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); link_state_id ++; } /* Point-to-Point interfaces */ if (if_is_pointopoint (oi->interface)) { for (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 */ if (if_is_broadcast (oi->interface)) { /* If this router is not DR, and If this router not fully adjacent with DR, this interface is not transit yet: ignore. */ if (oi->state != OSPF6_INTERFACE_DR) { drouter = ospf6_neighbor_lookup (oi->drouter, oi); if (drouter == NULL || drouter->state != OSPF6_NEIGHBOR_FULL) continue; } lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK; lsdesc->metric = htons (oi->cost); lsdesc->interface_id = htonl (oi->interface->ifindex); if (oi->state != OSPF6_INTERFACE_DR) { lsdesc->neighbor_interface_id = htonl (drouter->ifindex); lsdesc->neighbor_router_id = drouter->router_id; } else { lsdesc->neighbor_interface_id = htonl (oi->interface->ifindex); lsdesc->neighbor_router_id = oi->area->ospf6->router_id; } lsdesc++; } /* Virtual links */ /* xxx */ /* Point-to-Multipoint interfaces */ /* xxx */ } if ((caddr_t) lsdesc != (caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)) { /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); lsa_header->id = htonl (link_state_id); lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oa); link_state_id ++; } else { if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) zlog_debug ("Nothing to describe in Router-LSA, suppress"); } /* Do premature-aging of rest, undesired Router-LSAs */ type = ntohs (OSPF6_LSTYPE_ROUTER); router = oa->ospf6->router_id; for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) { if (ntohl (lsa->header->id) < link_state_id) continue; ospf6_lsa_purge (lsa); } return 0; } /*******************************/ /* RFC2740 3.4.3.2 Network-LSA */ /*******************************/ 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 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 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]; 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; } prefix_num = ntohs (intra_prefix_lsa->prefix_num); start = (caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); end = OSPF6_LSA_END (lsa->header); for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op)) { op = (struct ospf6_prefix *) current; if (prefix_num == 0) break; if (end < current + OSPF6_PREFIX_SIZE (op)) break; route = ospf6_route_create (); memset (&route->prefix, 0, sizeof (struct prefix)); route->prefix.family = AF_INET6; route->prefix.prefixlen = op->prefix_length; ospf6_prefix_in6_addr (&route->prefix.u.prefix6, op); route->type = OSPF6_DEST_TYPE_NETWORK; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.prefix_options = op->prefix_options; route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.metric_type = 1; route->path.cost = ls_entry->path.cost + ntohs (op->prefix_metric); for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_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; 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 = 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; 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 = 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", brouter->prev, brouter, brouter->next, 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, *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", 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; 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", 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 = 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", ospf6_router_lsa_show }; struct ospf6_lsa_handler network_handler = { OSPF6_LSTYPE_NETWORK, "Network", ospf6_network_lsa_show }; struct ospf6_lsa_handler link_handler = { OSPF6_LSTYPE_LINK, "Link", ospf6_link_lsa_show }; struct ospf6_lsa_handler intra_prefix_handler = { OSPF6_LSTYPE_INTRA_PREFIX, "Intra-Prefix", ospf6_intra_prefix_lsa_show }; void ospf6_intra_init (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-0.99.22.4/ospf6d/ospf6_intra.h0000644000175000017500000002040012045513244014025 00000000000000/* * 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 #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) \ (oa)->thread_router_lsa = \ thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \ } while (0) #define OSPF6_NETWORK_LSA_SCHEDULE(oi) \ do { \ if (! (oi)->thread_network_lsa) \ (oi)->thread_network_lsa = \ thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \ } while (0) #define OSPF6_LINK_LSA_SCHEDULE(oi) \ do { \ if (! (oi)->thread_link_lsa) \ (oi)->thread_link_lsa = \ thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \ do { \ if (! (oa)->thread_intra_prefix_lsa) \ (oa)->thread_intra_prefix_lsa = \ thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \ oa, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \ do { \ if (! (oi)->thread_intra_prefix_lsa) \ (oi)->thread_intra_prefix_lsa = \ thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \ oi, 0); \ } while (0) #define OSPF6_NETWORK_LSA_EXECUTE(oi) \ do { \ THREAD_OFF ((oi)->thread_network_lsa); \ thread_execute (master, ospf6_network_lsa_originate, oi, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi) \ do { \ THREAD_OFF ((oi)->thread_intra_prefix_lsa); \ thread_execute (master, ospf6_intra_prefix_lsa_originate_transit, oi, 0); \ } while (0) /* Function Prototypes */ 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_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-0.99.22.4/ospf6d/ospf6_lsa.c0000644000175000017500000006632412177450262013507 00000000000000/* * 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", ospf6_unknown_lsa_show, OSPF6_LSA_DEBUG, }; void ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler) { /* type in handler is host byte order */ int index = handler->type & OSPF6_LSTYPE_FCODE_MASK; vector_set_index (ospf6_lsa_handler_vector, index, handler); } struct ospf6_lsa_handler * ospf6_get_lsa_handler (u_int16_t type) { struct ospf6_lsa_handler *handler = NULL; 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; } u_char ospf6_lstype_debug (u_int16_t type) { struct ospf6_lsa_handler *handler; handler = ospf6_get_lsa_handler (type); return handler->debug; } /* RFC2328: Section 13.2 */ int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) { int len; assert (OSPF6_LSA_IS_SAME (lsa1, lsa2)); /* XXX, Options ??? */ ospf6_lsa_age_current (lsa1); ospf6_lsa_age_current (lsa2); if (ntohs (lsa1->header->age) == MAXAGE && ntohs (lsa2->header->age) != MAXAGE) return 1; if (ntohs (lsa1->header->age) != MAXAGE && ntohs (lsa2->header->age) == MAXAGE) return 1; /* compare body */ if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) return 1; len = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header); return memcmp (lsa1->header + 1, lsa2->header + 1, len); } int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) { int length; if (OSPF6_LSA_IS_MAXAGE (lsa1) ^ OSPF6_LSA_IS_MAXAGE (lsa2)) return 1; if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) return 1; /* 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) >= 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 (MAXAGE); return MAXAGE; } /* calculate age */ ulage = now.tv_sec - lsa->birth.tv_sec; /* if over MAXAGE, set to it */ age = (ulage > MAXAGE ? MAXAGE : ulage); lsa->header->age = htons (age); return age; } /* update age field of LSA header with adding InfTransDelay */ void ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) { unsigned short age; age = ospf6_lsa_age_current (lsa) + transdelay; if (age > MAXAGE) age = MAXAGE; lsa->header->age = htons (age); } void ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) { /* log */ if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) zlog_debug ("LSA: Premature aging: %s", lsa->name); THREAD_OFF (lsa->expire); THREAD_OFF (lsa->refresh); lsa->header->age = htons (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) { int 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 = (int) ntohl (a->header->seqnum); seqnumb = (int) 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 == MAXAGE && ageb != MAXAGE) return -1; else if (agea != MAXAGE && ageb == MAXAGE) return 1; /* Age check */ if (agea > ageb && agea - ageb >= MAX_AGE_DIFF) return 1; else if (agea < ageb && ageb - agea >= MAX_AGE_DIFF) return -1; /* neither recent */ return 0; } char * ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size) { char id[16], adv_router[16]; inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); snprintf (buf, size, "[%s Id:%s Adv:%s]", ospf6_lstype_name (lsa->header->type), id, adv_router); return buf; } void ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header) { char id[16], adv_router[16]; inet_ntop (AF_INET, &header->id, id, sizeof (id)); inet_ntop (AF_INET, &header->adv_router, adv_router, sizeof (adv_router)); zlog_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, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s", "Type", "LSId", "AdvRouter", "Age", "SeqNum", "Cksm", "Len", "Duration", VNL); } void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[16], id[16]; struct timeval now, res; char duration[16]; assert (lsa); assert (lsa->header); inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &lsa->installed, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s", ospf6_lstype_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum), ntohs (lsa->header->checksum), ntohs (lsa->header->length), duration, VNL); } void ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa) { u_char *start, *end, *current; char byte[4]; start = (u_char *) lsa->header; end = (u_char *) lsa->header + ntohs (lsa->header->length); vty_out (vty, "%s", VNL); vty_out (vty, "%s:%s", lsa->name, VNL); for (current = start; current < end; current ++) { if ((current - start) % 16 == 0) vty_out (vty, "%s ", VNL); else if ((current - start) % 4 == 0) vty_out (vty, " "); snprintf (byte, sizeof (byte), "%02x", *current); vty_out (vty, "%s", byte); } vty_out (vty, "%s%s", VNL, VNL); return; } void ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[64], id[64]; assert (lsa && lsa->header); inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); vty_out (vty, "%s", VNL); vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), ospf6_lstype_name (lsa->header->type), VNL); vty_out (vty, "Link State ID: %s%s", id, VNL); vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); vty_out (vty, "LS Sequence Number: %#010lx%s", (u_long) ntohl (lsa->header->seqnum), VNL); vty_out (vty, "CheckSum: %#06hx Length: %hu%s", ntohs (lsa->header->checksum), ntohs (lsa->header->length), VNL); vty_out (vty, " Prev: %p This: %p Next: %p%s", lsa->prev, lsa, lsa->next, VNL); vty_out (vty, "%s", VNL); return; } void ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[64], id[64]; struct ospf6_lsa_handler *handler; assert (lsa && lsa->header); inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), ospf6_lstype_name (lsa->header->type), VNL); vty_out (vty, "Link State ID: %s%s", id, VNL); vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); vty_out (vty, "LS Sequence Number: %#010lx%s", (u_long) ntohl (lsa->header->seqnum), VNL); vty_out (vty, "CheckSum: %#06hx Length: %hu%s", ntohs (lsa->header->checksum), ntohs (lsa->header->length), VNL); handler = ospf6_get_lsa_handler (lsa->header->type); if (handler->show == NULL) handler = &unknown_handler; (*handler->show) (vty, lsa); vty_out (vty, "%s", VNL); } /* OSPFv3 LSA creation/deletion function */ struct ospf6_lsa * ospf6_lsa_create (struct ospf6_lsa_header *header) { struct ospf6_lsa *lsa = NULL; struct ospf6_lsa_header *new_header = NULL; u_int16_t lsa_size = 0; /* size of the entire LSA */ lsa_size = ntohs (header->length); /* XXX vulnerable */ /* allocate memory for this LSA */ new_header = (struct ospf6_lsa_header *) XMALLOC (MTYPE_OSPF6_LSA, lsa_size); /* copy LSA from original header */ memcpy (new_header, header, lsa_size); /* LSA information structure */ /* allocate memory */ lsa = (struct ospf6_lsa *) 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; 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 ... */ /* reflood lsa */ ospf6_flood (NULL, lsa); /* reinstall lsa */ ospf6_install_lsa (lsa); /* schedule maxage remover */ ospf6_maxage_remove (ospf6); return 0; } int ospf6_lsa_refresh (struct thread *thread) { struct ospf6_lsa *old, *self, *new; struct ospf6_lsdb *lsdb_self; assert (thread); old = (struct ospf6_lsa *) THREAD_ARG (thread); assert (old && old->header); old->refresh = (struct thread *) NULL; lsdb_self = ospf6_get_scoped_lsdb_self (old); self = ospf6_lsdb_lookup (old->header->type, old->header->id, old->header->adv_router, lsdb_self); if (self == NULL) { if (IS_OSPF6_DEBUG_LSA_TYPE (old->header->type)) zlog_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, 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_flood_clear (old); ospf6_flood (NULL, new); ospf6_install_lsa (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 (h->name[i])) buf[i] = tolower (h->name[i]); else buf[i] = h->name[i]; } buf[size] = '\0'; return buf; } DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, "debug ospf6 lsa XXXX/0xXXXX", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) { unsigned int i; struct ospf6_lsa_handler *handler = NULL; unsigned long val; char *endptr = NULL; u_int16_t type = 0; assert (argc); if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) || (strlen (argv[0]) == 4)) { val = strtoul (argv[0], &endptr, 16); if (*endptr == '\0') type = val; } for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (type && handler->type == type) break; if (! strcasecmp (argv[0], handler->name)) break; handler = NULL; } if (type && handler == NULL) { handler = (struct ospf6_lsa_handler *) malloc (sizeof (struct ospf6_lsa_handler)); memset (handler, 0, sizeof (struct ospf6_lsa_handler)); handler->type = type; handler->name = "Unknown"; handler->show = ospf6_unknown_lsa_show; vector_set_index (ospf6_lsa_handler_vector, handler->type & OSPF6_LSTYPE_FCODE_MASK, handler); } if (handler == NULL) handler = &unknown_handler; if (argc >= 2) { if (! strcmp (argv[1], "originate")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); if (! strcmp (argv[1], "examin")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); if (! strcmp (argv[1], "flooding")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); } else SET_FLAG (handler->debug, OSPF6_LSA_DEBUG); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, "no debug ospf6 lsa XXXX/0xXXXX", NO_STR DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) { u_int i; struct ospf6_lsa_handler *handler = NULL; unsigned long val; char *endptr = NULL; u_int16_t type = 0; assert (argc); if ((strlen (argv[0]) == 6 && ! strncmp (argv[0], "0x", 2)) || (strlen (argv[0]) == 4)) { val = strtoul (argv[0], &endptr, 16); if (*endptr == '\0') type = val; } for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (type && handler->type == type) break; if (! strcasecmp (argv[0], handler->name)) break; } if (handler == NULL) return CMD_SUCCESS; if (argc >= 2) { if (! strcmp (argv[1], "originate")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); if (! strcmp (argv[1], "examin")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); if (! strcmp (argv[1], "flooding")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); } else UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG); if (handler->debug == 0 && !strcmp(handler->name, "Unknown") && type != OSPF6_LSTYPE_UNKNOWN) { free (handler); vector_slot (ospf6_lsa_handler_vector, i) = NULL; } return CMD_SUCCESS; } struct cmd_element debug_ospf6_lsa_type_cmd; struct cmd_element debug_ospf6_lsa_type_detail_cmd; struct cmd_element no_debug_ospf6_lsa_type_cmd; struct cmd_element no_debug_ospf6_lsa_type_detail_cmd; void install_element_ospf6_debug_lsa (void) { u_int i; struct ospf6_lsa_handler *handler; #define STRSIZE 256 #define DOCSIZE 1024 static char strbuf[STRSIZE]; static char docbuf[DOCSIZE]; static char detail_strbuf[STRSIZE]; static char detail_docbuf[DOCSIZE]; char *str, *no_str; char *doc, *no_doc; strbuf[0] = '\0'; no_str = &strbuf[strlen (strbuf)]; strncat (strbuf, "no ", STRSIZE - strlen (strbuf)); str = &strbuf[strlen (strbuf)]; strncat (strbuf, "debug ospf6 lsa (", STRSIZE - strlen (strbuf)); for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; strncat (strbuf, ospf6_lsa_handler_name (handler), STRSIZE - strlen (strbuf)); strncat (strbuf, "|", STRSIZE - strlen (strbuf)); } strbuf[strlen (strbuf) - 1] = ')'; strbuf[strlen (strbuf)] = '\0'; docbuf[0] = '\0'; no_doc = &docbuf[strlen (docbuf)]; strncat (docbuf, NO_STR, DOCSIZE - strlen (docbuf)); doc = &docbuf[strlen (docbuf)]; strncat (docbuf, DEBUG_STR, DOCSIZE - strlen (docbuf)); strncat (docbuf, OSPF6_STR, DOCSIZE - strlen (docbuf)); strncat (docbuf, "Debug Link State Advertisements (LSAs)\n", DOCSIZE - strlen (docbuf)); for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; strncat (docbuf, "Debug ", DOCSIZE - strlen (docbuf)); strncat (docbuf, handler->name, DOCSIZE - strlen (docbuf)); strncat (docbuf, "-LSA\n", DOCSIZE - strlen (docbuf)); } docbuf[strlen (docbuf)] = '\0'; debug_ospf6_lsa_type_cmd.string = str; debug_ospf6_lsa_type_cmd.func = debug_ospf6_lsa_type; debug_ospf6_lsa_type_cmd.doc = doc; no_debug_ospf6_lsa_type_cmd.string = no_str; no_debug_ospf6_lsa_type_cmd.func = no_debug_ospf6_lsa_type; no_debug_ospf6_lsa_type_cmd.doc = no_doc; strncpy (detail_strbuf, strbuf, STRSIZE); strncat (detail_strbuf, " (originate|examin|flooding)", STRSIZE - strlen (detail_strbuf)); detail_strbuf[strlen (detail_strbuf)] = '\0'; no_str = &detail_strbuf[0]; str = &detail_strbuf[strlen ("no ")]; strncpy (detail_docbuf, docbuf, DOCSIZE); strncat (detail_docbuf, "Debug Originating LSA\n", DOCSIZE - strlen (detail_docbuf)); strncat (detail_docbuf, "Debug Examining LSA\n", DOCSIZE - strlen (detail_docbuf)); strncat (detail_docbuf, "Debug Flooding LSA\n", DOCSIZE - strlen (detail_docbuf)); detail_docbuf[strlen (detail_docbuf)] = '\0'; no_doc = &detail_docbuf[0]; doc = &detail_docbuf[strlen (NO_STR)]; debug_ospf6_lsa_type_detail_cmd.string = str; debug_ospf6_lsa_type_detail_cmd.func = debug_ospf6_lsa_type; debug_ospf6_lsa_type_detail_cmd.doc = doc; no_debug_ospf6_lsa_type_detail_cmd.string = no_str; no_debug_ospf6_lsa_type_detail_cmd.func = no_debug_ospf6_lsa_type; no_debug_ospf6_lsa_type_detail_cmd.doc = no_doc; install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); install_element (ENABLE_NODE, &debug_ospf6_lsa_type_cmd); install_element (ENABLE_NODE, &debug_ospf6_lsa_type_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_type_detail_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_type_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_type_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_type_detail_cmd); } int config_write_ospf6_debug_lsa (struct vty *vty) { 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 examin%s", ospf6_lsa_handler_name (handler), VNL); if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD)) vty_out (vty, "debug ospf6 lsa %s flooding%s", ospf6_lsa_handler_name (handler), VNL); } return 0; } quagga-0.99.22.4/ospf6d/ospf6_lsa.h0000644000175000017500000002334612177450262013511 00000000000000/* * 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) == MAXAGE) #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) struct ospf6_lsa { char name[64]; /* dump string */ struct ospf6_lsa *prev; struct ospf6_lsa *next; unsigned char lock; /* reference counter */ unsigned char flag; /* special meaning (e.g. floodback) */ struct timeval birth; /* tv_sec when LS age 0 */ struct timeval originated; /* used by MinLSInterval check */ struct timeval received; /* used by MinLSArrival check */ struct timeval installed; struct thread *expire; struct thread *refresh; /* For self-originated LSA */ int retrans_count; struct ospf6_lsdb *lsdb; /* lsa instance */ struct ospf6_lsa_header *header; }; #define OSPF6_LSA_HEADERONLY 0x01 #define OSPF6_LSA_FLOODBACK 0x02 #define OSPF6_LSA_DUPLICATE 0x04 #define OSPF6_LSA_IMPLIEDACK 0x08 struct ospf6_lsa_handler { u_int16_t type; /* host byte order */ const char *name; int (*show) (struct vty *, struct ospf6_lsa *); u_char debug; }; extern struct ospf6_lsa_handler unknown_handler; #define OSPF6_LSA_IS_KNOWN(type) \ (ospf6_get_lsa_handler (type) != &unknown_handler ? 1 : 0) /* Macro for LSA Origination */ /* addr is (struct prefix *) */ #define CONTINUE_IF_ADDRESS_LINKLOCAL(debug,addr) \ if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6)) \ { \ char buf[64]; \ prefix2str (addr, buf, sizeof (buf)); \ if (debug) \ zlog_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 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-0.99.22.4/ospf6d/ospf6_lsdb.c0000644000175000017500000003400112000052240013612 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "memory.h" #include "log.h" #include "command.h" #include "prefix.h" #include "table.h" #include "vty.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6d.h" struct ospf6_lsdb * ospf6_lsdb_create (void *data) { struct ospf6_lsdb *lsdb; lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb)); if (lsdb == NULL) { zlog_warn ("Can't malloc lsdb"); return NULL; } memset (lsdb, 0, sizeof (struct ospf6_lsdb)); lsdb->data = data; lsdb->table = route_table_init (); return lsdb; } void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb) { ospf6_lsdb_remove_all (lsdb); route_table_finish (lsdb->table); XFREE (MTYPE_OSPF6_LSDB, lsdb); } static void ospf6_lsdb_set_key (struct prefix_ipv6 *key, void *value, int len) { assert (key->prefixlen % 8 == 0); memcpy ((caddr_t) &key->prefix + key->prefixlen / 8, (caddr_t) value, len); key->family = AF_INET6; key->prefixlen += len * 8; } #ifndef NDEBUG static void _lsdb_count_assert (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *debug; 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 /*NDEBUG*/ #define ospf6_lsdb_count_assert(t) ((void) 0) #endif /*NDEBUG*/ void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct prefix_ipv6 key; struct route_node *current, *nextnode, *prevnode; struct ospf6_lsa *next, *prev, *old = NULL; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type)); ospf6_lsdb_set_key (&key, &lsa->header->adv_router, sizeof (lsa->header->adv_router)); ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id)); current = route_node_get (lsdb->table, (struct prefix *) &key); old = current->info; current->info = lsa; ospf6_lsa_lock (lsa); if (old) { if (old->prev) old->prev->next = lsa; if (old->next) old->next->prev = lsa; lsa->next = old->next; lsa->prev = old->prev; } else { /* next link */ nextnode = current; route_lock_node (nextnode); do { nextnode = route_next (nextnode); } while (nextnode && nextnode->info == NULL); if (nextnode == NULL) lsa->next = NULL; else { next = nextnode->info; lsa->next = next; next->prev = lsa; route_unlock_node (nextnode); } /* prev link */ prevnode = current; route_lock_node (prevnode); do { prevnode = route_prev (prevnode); } while (prevnode && prevnode->info == NULL); if (prevnode == NULL) lsa->prev = NULL; else { prev = prevnode->info; lsa->prev = prev; prev->next = lsa; route_unlock_node (prevnode); } lsdb->count++; } if (old) { if (OSPF6_LSA_IS_CHANGED (old, lsa)) { if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (lsdb->hook_remove) { (*lsdb->hook_remove) (old); (*lsdb->hook_remove) (lsa); } } else if (OSPF6_LSA_IS_MAXAGE (old)) { if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } else { if (lsdb->hook_remove) (*lsdb->hook_remove) (old); if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } } } else if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); } else { if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } if (old) ospf6_lsa_unlock (old); 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); if (lsa->prev) lsa->prev->next = lsa->next; if (lsa->next) lsa->next->prev = lsa->prev; node->info = NULL; lsdb->count--; if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); ospf6_lsa_unlock (lsa); route_unlock_node (node); ospf6_lsdb_count_assert (lsdb); } struct ospf6_lsa * ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; if (lsdb == NULL) return NULL; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); ospf6_lsdb_set_key (&key, &id, sizeof (id)); node = route_node_lookup (lsdb->table, (struct prefix *) &key); if (node == NULL || node->info == NULL) return NULL; return (struct ospf6_lsa *) node->info; } 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)) { struct route_node *prev = node; struct ospf6_lsa *lsa_prev; struct ospf6_lsa *lsa_next; node = route_next (node); while (node && node->info == NULL) node = route_next (node); lsa_prev = prev->info; lsa_next = (node ? node->info : NULL); assert (lsa_prev); assert (lsa_prev->next == lsa_next); if (lsa_next) assert (lsa_next->prev == lsa_prev); zlog_debug ("lsdb_lookup_next: assert OK with previous LSA"); } if (! node) return NULL; route_unlock_node (node); return (struct ospf6_lsa *) node->info; } /* Iteration function */ struct ospf6_lsa * ospf6_lsdb_head (struct ospf6_lsdb *lsdb) { struct route_node *node; node = route_top (lsdb->table); if (node == NULL) return NULL; /* skip to the existing lsdb entry */ while (node && node->info == NULL) node = route_next (node); if (node == NULL) return NULL; route_unlock_node (node); if (node->info) ospf6_lsa_lock ((struct ospf6_lsa *) node->info); return (struct ospf6_lsa *) node->info; } struct ospf6_lsa * ospf6_lsdb_next (struct ospf6_lsa *lsa) { struct ospf6_lsa *next = lsa->next; ospf6_lsa_unlock (lsa); if (next) ospf6_lsa_lock (next); return next; } struct ospf6_lsa * ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; struct ospf6_lsa *lsa; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); node = lsdb->table->top; /* Walk down tree. */ while (node && node->p.prefixlen <= key.prefixlen && prefix_match (&node->p, (struct prefix *) &key)) node = node->link[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; else route_unlock_node (node); if (! prefix_match ((struct prefix *) &key, &node->p)) return NULL; lsa = node->info; ospf6_lsa_lock (lsa); return lsa; } struct ospf6_lsa * ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router, struct ospf6_lsa *lsa) { struct ospf6_lsa *next = lsa->next; if (next) { if (next->header->type != type || next->header->adv_router != adv_router) next = NULL; } if (next) ospf6_lsa_lock (next); ospf6_lsa_unlock (lsa); return next; } struct ospf6_lsa * ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; struct ospf6_lsa *lsa; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); /* Walk down tree. */ node = lsdb->table->top; while (node && node->p.prefixlen <= key.prefixlen && prefix_match (&node->p, (struct prefix *) &key)) node = node->link[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; else route_unlock_node (node); if (! prefix_match ((struct prefix *) &key, &node->p)) return NULL; lsa = node->info; ospf6_lsa_lock (lsa); return lsa; } struct ospf6_lsa * ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa) { struct ospf6_lsa *next = lsa->next; if (next) { if (next->header->type != type) next = NULL; } if (next) ospf6_lsa_lock (next); ospf6_lsa_unlock (lsa); return next; } void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) ospf6_lsdb_remove (lsa, lsdb); } void ospf6_lsdb_show (struct vty *vty, int level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL; if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) showfunc = ospf6_lsa_show_summary; else if (level == OSPF6_LSDB_SHOW_LEVEL_DETAIL) showfunc = ospf6_lsa_show; else if (level == OSPF6_LSDB_SHOW_LEVEL_INTERNAL) showfunc = ospf6_lsa_show_internal; else if (level == OSPF6_LSDB_SHOW_LEVEL_DUMP) showfunc = ospf6_lsa_show_dump; if (type && id && adv_router) { lsa = ospf6_lsdb_lookup (*type, *id, *adv_router, lsdb); if (lsa) { if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) ospf6_lsa_show (vty, lsa); else (*showfunc) (vty, lsa); } return; } if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) ospf6_lsa_show_summary_header (vty); if (type && adv_router) lsa = ospf6_lsdb_type_router_head (*type, *adv_router, lsdb); else if (type) lsa = ospf6_lsdb_type_head (*type, lsdb); else lsa = ospf6_lsdb_head (lsdb); while (lsa) { if ((! adv_router || lsa->header->adv_router == *adv_router) && (! id || lsa->header->id == *id)) (*showfunc) (vty, lsa); if (type && adv_router) lsa = ospf6_lsdb_type_router_next (*type, *adv_router, lsa); else if (type) lsa = ospf6_lsdb_type_next (*type, lsa); else lsa = ospf6_lsdb_next (lsa); } } /* Decide new Link State ID to originate. note return value is network byte order */ u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; u_int32_t id = 1; for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) { if (ntohl (lsa->header->id) < id) continue; if (ntohl (lsa->header->id) > id) { ospf6_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 = INITIAL_SEQUENCE_NUMBER; else seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; return ((u_int32_t) htonl (seqnum)); } quagga-0.99.22.4/ospf6d/ospf6_lsdb.h0000644000175000017500000001052012000052240013617 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_LSDB_H #define OSPF6_LSDB_H #include "prefix.h" #include "table.h" struct ospf6_lsdb { void *data; /* data structure that holds this lsdb */ struct route_table *table; u_int32_t count; void (*hook_add) (struct ospf6_lsa *); void (*hook_remove) (struct ospf6_lsa *); }; #define OSPF6_LSDB_MAXAGE_REMOVER(lsdb) \ do { \ struct ospf6_lsa *lsa; \ for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) \ { \ if (! OSPF6_LSA_IS_MAXAGE (lsa)) \ continue; \ if (lsa->retrans_count != 0) \ continue; \ if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) \ zlog_debug ("Remove MaxAge %s", lsa->name); \ ospf6_lsdb_remove (lsa, lsdb); \ } \ } while (0) /* 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); #define OSPF6_LSDB_SHOW_LEVEL_NORMAL 0 #define OSPF6_LSDB_SHOW_LEVEL_DETAIL 1 #define OSPF6_LSDB_SHOW_LEVEL_INTERNAL 2 #define OSPF6_LSDB_SHOW_LEVEL_DUMP 3 extern void ospf6_lsdb_show (struct vty *vty, int level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb); 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); #endif /* OSPF6_LSDB_H */ quagga-0.99.22.4/ospf6d/ospf6_main.c0000644000175000017500000001767212211704467013654 00000000000000/* * 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 "ospf6d.h" #include "ospf6_top.h" #include "ospf6_message.h" #include "ospf6_asbr.h" #include "ospf6_lsa.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 zebra@zebra.org\n", progname); } exit (status); } static void __attribute__ ((noreturn)) ospf6_exit (int status) { extern struct ospf6 *ospf6; extern struct zclient *zclient; if (ospf6) ospf6_delete (ospf6); ospf6_message_terminate (); ospf6_asbr_terminate (); ospf6_lsa_terminate (); if_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; struct thread thread; 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 (); if_init (); access_list_init (); prefix_list_init (); /* initialize ospf6 */ ospf6_init (); /* sort command vector */ sort_node (); /* parse config file */ vty_read_config (config_file, config_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! */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Log in case thread failed */ zlog_warn ("Thread failed"); /* Not reached. */ ospf6_exit (0); } quagga-0.99.22.4/ospf6d/ospf6_message.c0000644000175000017500000023035712177450262014353 00000000000000/* * 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 (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 (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->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 (his, on->request_list); } else 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->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 == BACKBONE_AREA_ID) 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)); /* RFC2328 Section 10.9: When the neighbor responds to these requests with the proper Link State Update packet(s), the Link state request list is truncated and a new Link State Request packet is sent. */ /* send new Link State Request packet if this LS Update packet can be recognized as a response to our previous LS Request */ if (! IN6_IS_ADDR_MULTICAST (dst) && (on->state == OSPF6_NEIGHBOR_EXCHANGE || on->state == OSPF6_NEIGHBOR_LOADING)) { THREAD_OFF (on->thread_send_lsreq); on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); } } 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; unsigned int ifindex; struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; /* add next read thread */ sockfd = THREAD_FD (thread); thread_add_read (master, ospf6_receive, NULL, sockfd); /* initialize */ memset (&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) { 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) { 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; } /* 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; 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)) { 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_lsa_unlock (lsa); break; } memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); p += sizeof (struct ospf6_lsa_header); } } oh->type = OSPF6_MESSAGE_TYPE_DBDESC; oh->length = htons (p - sendbuf); ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); return 0; } int ospf6_dbdesc_send_newone (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; unsigned int size = 0; on = (struct ospf6_neighbor *) THREAD_ARG (thread); ospf6_lsdb_remove_all (on->dbdesc_list); /* move LSAs from summary_list to dbdesc_list (within neighbor structure) so that ospf6_send_dbdesc () can send those LSAs */ size = sizeof (struct ospf6_lsa_header) + sizeof (struct ospf6_dbdesc); for (lsa = ospf6_lsdb_head (on->summary_list); lsa; lsa = ospf6_lsdb_next (lsa)) { if (size + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; } ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->dbdesc_list); ospf6_lsdb_remove (lsa, on->summary_list); size += sizeof (struct ospf6_lsa_header); } if (on->summary_list->count == 0) UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); /* If slave, More bit check must be done here */ if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */ ! CHECK_FLAG (on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) && ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) thread_add_event (master, exchange_done, on, 0); thread_execute (master, ospf6_dbdesc_send, on, 0); return 0; } int ospf6_lsreq_send (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; struct ospf6_lsreq_entry *e; u_char *p; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsreq = (struct thread *) NULL; /* LSReq will be sent only in ExStart or Loading */ if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSREQ, SEND)) zlog_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; } /* set next thread */ on->thread_send_lsreq = thread_add_timer (master, ospf6_lsreq_send, on, on->ospf6_if->rxmt_interval); memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; /* set Request entries in lsreq */ p = (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_lsa_unlock (lsa); break; } e = (struct ospf6_lsreq_entry *) p; e->type = lsa->header->type; e->id = lsa->header->id; e->adv_router = lsa->header->adv_router; p += sizeof (struct ospf6_lsreq_entry); } oh->type = OSPF6_MESSAGE_TYPE_LSREQ; oh->length = htons (p - sendbuf); ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); return 0; } int ospf6_lsupdate_send_neighbor (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; int num; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsupdate = (struct thread *) NULL; if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_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; } /* if we have nothing to send, return */ if (on->lsupdate_list->count == 0 && on->retrans_list->count == 0) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_debug ("Quit to send (nothing to send)"); return 0; } memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); num = 0; /* lsupdate_list lists those LSA which doesn't need to be retransmitted. remove those from the list */ for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); num++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsupdate_list); } for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); num++; } lsupdate->lsa_number = htonl (num); oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); if (on->lsupdate_list->count != 0 || on->retrans_list->count != 0) { if (on->lsupdate_list->count != 0) on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); else on->thread_send_lsupdate = thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, on->ospf6_if->rxmt_interval); } return 0; } int ospf6_lsupdate_send_interface (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; int num; struct ospf6_lsa *lsa; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_send_lsupdate = (struct thread *) NULL; if (oi->state <= OSPF6_INTERFACE_WAITING) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_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)); num = 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_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, oi->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); num++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsupdate_list); } lsupdate->lsa_number = htonl (num); oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); if (oi->state == OSPF6_INTERFACE_DR || oi->state == OSPF6_INTERFACE_BDR) ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); else ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); if (oi->lsupdate_list->count > 0) { oi->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); } return 0; } int ospf6_lsack_send_neighbor (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsack = (struct thread *) NULL; if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) zlog_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_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); p += sizeof (struct ospf6_lsa_header); assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsack_list); } oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons (p - sendbuf); ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); return 0; } int ospf6_lsack_send_interface (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_send_lsack = (struct thread *) NULL; if (oi->state <= OSPF6_INTERFACE_WAITING) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) zlog_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_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, oi->transdelay); memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); p += sizeof (struct ospf6_lsa_header); assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsack_list); } oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons (p - sendbuf); if (oi->state == OSPF6_INTERFACE_DR || oi->state == OSPF6_INTERFACE_BDR) ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); else ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); if (oi->thread_send_lsack == NULL && oi->lsack_list->count > 0) { oi->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_interface, oi, 0); } return 0; } /* Commands */ DEFUN (debug_ospf6_message, debug_ospf6_message_cmd, "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" ) { unsigned char level = 0; int type = 0; int i; assert (argc > 0); /* check type */ if (! strncmp (argv[0], "u", 1)) type = OSPF6_MESSAGE_TYPE_UNKNOWN; else if (! strncmp (argv[0], "h", 1)) type = OSPF6_MESSAGE_TYPE_HELLO; else if (! strncmp (argv[0], "d", 1)) type = OSPF6_MESSAGE_TYPE_DBDESC; else if (! strncmp (argv[0], "lsr", 3)) type = OSPF6_MESSAGE_TYPE_LSREQ; else if (! strncmp (argv[0], "lsu", 3)) type = OSPF6_MESSAGE_TYPE_LSUPDATE; else if (! strncmp (argv[0], "lsa", 3)) type = OSPF6_MESSAGE_TYPE_LSACK; else if (! strncmp (argv[0], "a", 1)) type = OSPF6_MESSAGE_TYPE_ALL; if (argc == 1) level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; else if (! strncmp (argv[1], "s", 1)) level = OSPF6_DEBUG_MESSAGE_SEND; else if (! strncmp (argv[1], "r", 1)) level = OSPF6_DEBUG_MESSAGE_RECV; if (type == OSPF6_MESSAGE_TYPE_ALL) { for (i = 0; i < 6; i++) OSPF6_DEBUG_MESSAGE_ON (i, level); } else OSPF6_DEBUG_MESSAGE_ON (type, level); return CMD_SUCCESS; } ALIAS (debug_ospf6_message, debug_ospf6_message_sendrecv_cmd, "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" "Debug only sending message\n" "Debug only receiving message\n" ) DEFUN (no_debug_ospf6_message, no_debug_ospf6_message_cmd, "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" ) { unsigned char level = 0; int type = 0; int i; assert (argc > 0); /* check type */ if (! strncmp (argv[0], "u", 1)) type = OSPF6_MESSAGE_TYPE_UNKNOWN; else if (! strncmp (argv[0], "h", 1)) type = OSPF6_MESSAGE_TYPE_HELLO; else if (! strncmp (argv[0], "d", 1)) type = OSPF6_MESSAGE_TYPE_DBDESC; else if (! strncmp (argv[0], "lsr", 3)) type = OSPF6_MESSAGE_TYPE_LSREQ; else if (! strncmp (argv[0], "lsu", 3)) type = OSPF6_MESSAGE_TYPE_LSUPDATE; else if (! strncmp (argv[0], "lsa", 3)) type = OSPF6_MESSAGE_TYPE_LSACK; else if (! strncmp (argv[0], "a", 1)) type = OSPF6_MESSAGE_TYPE_ALL; if (argc == 1) level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; else if (! strncmp (argv[1], "s", 1)) level = OSPF6_DEBUG_MESSAGE_SEND; else if (! strncmp (argv[1], "r", 1)) level = OSPF6_DEBUG_MESSAGE_RECV; if (type == OSPF6_MESSAGE_TYPE_ALL) { for (i = 0; i < 6; i++) OSPF6_DEBUG_MESSAGE_OFF (i, level); } else OSPF6_DEBUG_MESSAGE_OFF (type, level); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_message, no_debug_ospf6_message_sendrecv_cmd, "no debug ospf6 message " "(unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" "Debug only sending message\n" "Debug only receiving message\n" ) int config_write_ospf6_debug_message (struct vty *vty) { 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-0.99.22.4/ospf6d/ospf6_message.h0000644000175000017500000001075312101110036014327 00000000000000/* * 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-0.99.22.4/ospf6d/ospf6_neighbor.c0000644000175000017500000006526512177450262014530 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "thread.h" #include "linklist.h" #include "vty.h" #include "command.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_flood.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_neighbor = 0; const char *ospf6_neighbor_state_str[] = { "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange", "Loading", "Full", NULL }; int ospf6_neighbor_cmp (void *va, void *vb) { struct ospf6_neighbor *ona = (struct ospf6_neighbor *) va; struct ospf6_neighbor *onb = (struct ospf6_neighbor *) vb; return (ntohl (ona->router_id) < ntohl (onb->router_id) ? -1 : 1); } struct ospf6_neighbor * ospf6_neighbor_lookup (u_int32_t router_id, struct ospf6_interface *oi) { 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->lsreq_list = ospf6_lsdb_create (on); on->lsupdate_list = ospf6_lsdb_create (on); on->lsack_list = ospf6_lsdb_create (on); listnode_add_sort (oi->neighbor_list, on); return on; } void ospf6_neighbor_delete (struct ospf6_neighbor *on) { struct ospf6_lsa *lsa; ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } ospf6_lsdb_remove_all (on->dbdesc_list); ospf6_lsdb_remove_all (on->lsreq_list); ospf6_lsdb_remove_all (on->lsupdate_list); ospf6_lsdb_remove_all (on->lsack_list); ospf6_lsdb_delete (on->summary_list); ospf6_lsdb_delete (on->request_list); ospf6_lsdb_delete (on->retrans_list); ospf6_lsdb_delete (on->dbdesc_list); ospf6_lsdb_delete (on->lsreq_list); ospf6_lsdb_delete (on->lsupdate_list); ospf6_lsdb_delete (on->lsack_list); THREAD_OFF (on->inactivity_timer); THREAD_OFF (on->thread_send_dbdesc); THREAD_OFF (on->thread_send_lsreq); THREAD_OFF (on->thread_send_lsupdate); THREAD_OFF (on->thread_send_lsack); XFREE (MTYPE_OSPF6_NEIGHBOR, on); } static void ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on) { u_char prev_state; prev_state = on->state; on->state = next_state; if (prev_state == next_state) return; 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]", on->name, ospf6_neighbor_state_str[prev_state], ospf6_neighbor_state_str[next_state]); } if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL) { OSPF6_ROUTER_LSA_SCHEDULE (on->ospf6_if->area); if (on->ospf6_if->state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE (on->ospf6_if); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (on->ospf6_if); } OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (on->ospf6_if->area); } 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); 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); return 0; } ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return 0; } int negotiation_done (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state != OSPF6_NEIGHBOR_EXSTART) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_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); 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); else ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on); return 0; } int loading_done (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state != OSPF6_NEIGHBOR_LOADING) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *LoadingDone*", on->name); assert (on->request_list->count == 0); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on); return 0; } int adj_ok (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *AdjOK?*", on->name); if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency (on)) { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); } else if (on->state >= OSPF6_NEIGHBOR_EXSTART && ! need_adjacency (on)) { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } } return 0; } int seqnumber_mismatch (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *SeqNumberMismatch*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return 0; } int bad_lsreq (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *BadLSReq*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return 0; } int oneway_received (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state < OSPF6_NEIGHBOR_TWOWAY) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *1Way-Received*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on); thread_add_event (master, neighbor_change, on->ospf6_if, 0); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } THREAD_OFF (on->thread_send_dbdesc); THREAD_OFF (on->thread_send_lsreq); THREAD_OFF (on->thread_send_lsupdate); THREAD_OFF (on->thread_send_lsack); return 0; } int inactivity_timer (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_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); 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->lsreq_list->count, duration, (on->thread_send_lsreq ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->lsreq_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (on->thread_send_lsupdate) timersub (&on->thread_send_lsupdate->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]%s", on->lsupdate_list->count, duration, (on->thread_send_lsupdate ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (on->thread_send_lsack) timersub (&on->thread_send_lsack->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSAck in Time %s [thread %s]%s", on->lsack_list->count, duration, (on->thread_send_lsack ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->lsack_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); } DEFUN (show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd, "show ipv6 ospf6 neighbor", SHOW_STR IP6_STR OSPF6_STR "Neighbor list\n" ) { struct ospf6_neighbor *on; struct ospf6_interface *oi; struct ospf6_area *oa; 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); install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); } DEFUN (debug_ospf6_neighbor, debug_ospf6_neighbor_cmd, "debug ospf6 neighbor", DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_NEIGHBOR_STATE; if (! strncmp (argv[0], "e", 1)) level = OSPF6_DEBUG_NEIGHBOR_EVENT; } else level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; OSPF6_DEBUG_NEIGHBOR_ON (level); return CMD_SUCCESS; } ALIAS (debug_ospf6_neighbor, debug_ospf6_neighbor_detail_cmd, "debug ospf6 neighbor (state|event)", DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" "Debug OSPFv3 Neighbor State Change\n" "Debug OSPFv3 Neighbor Event\n" ) DEFUN (no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_cmd, "no debug ospf6 neighbor", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_NEIGHBOR_STATE; if (! strncmp (argv[0], "e", 1)) level = OSPF6_DEBUG_NEIGHBOR_EVENT; } else level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; OSPF6_DEBUG_NEIGHBOR_OFF (level); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_detail_cmd, "no debug ospf6 neighbor (state|event)", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" "Debug OSPFv3 Neighbor State Change\n" "Debug OSPFv3 Neighbor Event\n" ) int config_write_ospf6_debug_neighbor (struct vty *vty) { if (IS_OSPF6_DEBUG_NEIGHBOR (STATE) && IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) vty_out (vty, "debug ospf6 neighbor%s", VNL); else if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) vty_out (vty, "debug ospf6 neighbor state%s", VNL); else if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) vty_out (vty, "debug ospf6 neighbor event%s", VNL); return 0; } void install_element_ospf6_debug_neighbor (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-0.99.22.4/ospf6d/ospf6_neighbor.h0000644000175000017500000001013012177450262014512 00000000000000/* * 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 */ u_int32_t ifindex; /* Router Priority of this neighbor */ u_char priority; u_int32_t drouter; u_int32_t bdrouter; u_int32_t prev_drouter; u_int32_t prev_bdrouter; /* Options field (Capability) */ char options[3]; /* IPaddr of I/F on our side link */ struct in6_addr linklocal_addr; /* For Database Exchange */ u_char dbdesc_bits; u_int32_t dbdesc_seqnum; /* Last received Database Description packet */ struct ospf6_dbdesc dbdesc_last; /* LS-list */ struct ospf6_lsdb *summary_list; struct ospf6_lsdb *request_list; struct ospf6_lsdb *retrans_list; /* LSA list for message transmission */ struct ospf6_lsdb *dbdesc_list; struct ospf6_lsdb *lsreq_list; struct ospf6_lsdb *lsupdate_list; struct ospf6_lsdb *lsack_list; /* Inactivity timer */ struct thread *inactivity_timer; /* Thread for sending message */ struct thread *thread_send_dbdesc; struct thread *thread_send_lsreq; struct thread *thread_send_lsupdate; struct thread *thread_send_lsack; }; /* Neighbor state */ #define OSPF6_NEIGHBOR_DOWN 1 #define OSPF6_NEIGHBOR_ATTEMPT 2 #define OSPF6_NEIGHBOR_INIT 3 #define OSPF6_NEIGHBOR_TWOWAY 4 #define OSPF6_NEIGHBOR_EXSTART 5 #define OSPF6_NEIGHBOR_EXCHANGE 6 #define OSPF6_NEIGHBOR_LOADING 7 #define OSPF6_NEIGHBOR_FULL 8 extern 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_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-0.99.22.4/ospf6d/ospf6_network.c0000644000175000017500000001612112132522417014400 00000000000000/* * 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 "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 ReUseAddr to on */ void ospf6_set_reuseaddr (void) { u_int on = 0; if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (u_int)) < 0) zlog_warn ("Network: set SO_REUSEADDR failed: %s", safe_strerror (errno)); } /* setsockopt MulticastLoop to off */ 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)); } void ospf6_set_pktinfo (void) { setsockopt_ipv6_pktinfo (ospf6_sock, 1); } void ospf6_set_transport_class (void) { #ifdef IPTOS_PREC_INTERNETCONTROL setsockopt_ipv6_tclass (ospf6_sock, IPTOS_PREC_INTERNETCONTROL); #endif } 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 */ void ospf6_sso (u_int 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)); } 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, unsigned int *ifindex, struct iovec *message) { int retval; struct msghdr smsghdr; struct cmsghdr *scmsgp; u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; struct in6_pktinfo *pktinfo; struct sockaddr_in6 dst_sin6; assert (dst); assert (*ifindex); scmsgp = (struct cmsghdr *)cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); memset (&dst_sin6, 0, sizeof (struct sockaddr_in6)); /* source address */ pktinfo->ipi6_ifindex = *ifindex; if (src) memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr)); else memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr)); /* destination address */ dst_sin6.sin6_family = AF_INET6; #ifdef SIN6_LEN dst_sin6.sin6_len = sizeof (struct sockaddr_in6); #endif /*SIN6_LEN*/ memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr)); #ifdef HAVE_SIN6_SCOPE_ID dst_sin6.sin6_scope_id = *ifindex; #endif /* send control msg */ scmsgp->cmsg_level = IPPROTO_IPV6; scmsgp->cmsg_type = IPV6_PKTINFO; scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */ /* send msg hdr */ 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 = sizeof (cmsgbuf); 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, unsigned int *ifindex, struct iovec *message) { int retval; struct msghdr rmsghdr; struct cmsghdr *rcmsgp; u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; struct in6_pktinfo *pktinfo; struct sockaddr_in6 src_sin6; rcmsgp = (struct cmsghdr *)cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); /* receive control msg */ rcmsgp->cmsg_level = IPPROTO_IPV6; rcmsgp->cmsg_type = IPV6_PKTINFO; rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ /* receive msg hdr */ 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-0.99.22.4/ospf6d/ospf6_network.h0000644000175000017500000000277412101110036014400 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_NETWORK_H #define OSPF6_NETWORK_H extern int ospf6_sock; extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; /* Function Prototypes */ extern void ospf6_set_reuseaddr (void); extern void ospf6_reset_mcastloop (void); extern void ospf6_set_pktinfo (void); extern void ospf6_set_checksum (void); extern int ospf6_serv_sock (void); extern void ospf6_sso (u_int ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, unsigned int *, struct iovec *); extern int ospf6_recvmsg (struct in6_addr *, struct in6_addr *, unsigned int *, struct iovec *); #endif /* OSPF6_NETWORK_H */ quagga-0.99.22.4/ospf6d/ospf6_proto.c0000644000175000017500000000474112101110036014041 00000000000000/* * 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-0.99.22.4/ospf6d/ospf6_proto.h0000644000175000017500000001101612045513244014056 00000000000000/* * Common protocol data and data structures. * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_PROTO_H #define OSPF6_PROTO_H /* OSPF protocol version */ #define OSPFV3_VERSION 3 /* OSPF protocol number. */ #ifndef IPPROTO_OSPFIGP #define IPPROTO_OSPFIGP 89 #endif /* TOS field normaly null */ #define DEFAULT_TOS_VALUE 0x0 /* Architectural Constants */ #define LS_REFRESH_TIME 1800 /* 30 min */ #define MIN_LS_INTERVAL 5 #define MIN_LS_ARRIVAL 1 #define MAXAGE 3600 /* 1 hour */ #define CHECK_AGE 300 /* 5 min */ #define MAX_AGE_DIFF 900 /* 15 min */ #define LS_INFINITY 0xffffff /* 24-bit binary value */ #define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */ #define MAX_SEQUENCE_NUMBER 0x7fffffff /* signed 32-bit integer */ #define ALLSPFROUTERS6 "ff02::5" #define ALLDROUTERS6 "ff02::6" /* Configurable Constants */ #define DEFAULT_HELLO_INTERVAL 10 #define DEFAULT_ROUTER_DEAD_INTERVAL 40 #define OSPF6_ROUTER_BIT_W (1 << 3) #define OSPF6_ROUTER_BIT_V (1 << 2) #define OSPF6_ROUTER_BIT_E (1 << 1) #define OSPF6_ROUTER_BIT_B (1 << 0) /* OSPF options */ /* present in HELLO, DD, LSA */ #define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) #define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) #define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) #define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) #define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ #define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ #define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ #define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ #define OSPF6_OPT_E (1 << 1) /* AS External Capability */ #define OSPF6_OPT_V6 (1 << 0) /* IPv6 forwarding Capability */ /* OSPF6 Prefix */ #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-0.99.22.4/ospf6d/ospf6_route.c0000644000175000017500000011437412132522417014056 00000000000000/* * 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; } #ifndef NDEBUG 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 /*NDEBUG*/ struct ospf6_route * ospf6_route_add (struct ospf6_route *route, struct ospf6_route_table *table) { struct route_node *node, *nextnode, *prevnode; struct ospf6_route *current = NULL; struct ospf6_route *prev = NULL, *old = NULL, *next = NULL; char buf[64]; struct timeval now; assert (route->rnode == NULL); assert (route->lock == 0); assert (route->next == NULL); assert (route->prev == NULL); if (route->type == OSPF6_DEST_TYPE_LINKSTATE) ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); else prefix2str (&route->prefix, buf, sizeof (buf)); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table), table, 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), table, route, 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), table, route, 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), table, route, prev, 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), table, route, 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), table, 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), table, 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 && ospf6_route_is_same (route->next, route)) { node->info = route->next; SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); } else node->info = NULL; /* should unlock route_node here ? */ } table->count--; ospf6_route_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), table, route->prev, route, 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), route->table, route->prev, route, 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], ifname[IFNAMSIZ]; 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)); if (! if_indextoname (route->nexthop[0].ifindex, ifname)) snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %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; ospf6_nexthop_is_set (&route->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); if (! if_indextoname (route->nexthop[i].ifindex, ifname)) snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); } } void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) { char destination[64], nexthop[64], ifname[IFNAMSIZ]; char area_id[16], id[16], adv_router[16], capa[16], options[16]; struct timeval now, res; char duration[16]; int i; 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", route->prev, route, route->next, VNL); /* Path section */ /* Area-ID */ inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id)); vty_out (vty, "Associated Area: %s%s", area_id, VNL); /* Path type */ vty_out (vty, "Path Type: %s%s", OSPF6_PATH_TYPE_NAME (route->path.type), VNL); /* LS Origin */ inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id)); inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router, sizeof (adv_router)); vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s", ospf6_lstype_name (route->path.origin.type), id, adv_router, VNL); /* Options */ ospf6_options_printbuf (route->path.options, options, sizeof (options)); vty_out (vty, "Options: %s%s", options, VNL); /* Router Bits */ ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa)); vty_out (vty, "Router Bits: %s%s", capa, VNL); /* Prefix Options */ vty_out (vty, "Prefix Options: xxx%s", VNL); /* Metrics */ vty_out (vty, "Metric Type: %d%s", route->path.metric_type, VNL); vty_out (vty, "Metric: %d (%d)%s", route->path.cost, route->path.cost_e2, VNL); /* Nexthops */ vty_out (vty, "Nexthop:%s", VNL); for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); if (! if_indextoname (route->nexthop[i].ifindex, ifname)) snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); vty_out (vty, " %s %.*s%s", nexthop, 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-0.99.22.4/ospf6d/ospf6_route.h0000644000175000017500000002472412132522417014062 00000000000000/* * 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 */ unsigned int ifindex; /* IP address, if any */ struct in6_addr address; }; #define ospf6_nexthop_is_set(x) \ ((x)->ifindex || ! IN6_IS_ADDR_UNSPECIFIED (&(x)->address)) #define ospf6_nexthop_is_same(a,b) \ ((a)->ifindex == (b)->ifindex && \ IN6_ARE_ADDR_EQUAL (&(a)->address, &(b)->address)) #define ospf6_nexthop_clear(x) \ do { \ (x)->ifindex = 0; \ memset (&(x)->address, 0, sizeof (struct in6_addr)); \ } while (0) #define ospf6_nexthop_copy(a, b) \ do { \ (a)->ifindex = (b)->ifindex; \ memcpy (&(a)->address, &(b)->address, \ sizeof (struct in6_addr)); \ } while (0) /* Path */ struct ospf6_ls_origin { u_int16_t type; u_int32_t id; u_int32_t adv_router; }; struct ospf6_path { /* Link State Origin */ struct ospf6_ls_origin origin; /* Router bits */ u_char router_bits; /* Optional Capabilities */ u_char options[3]; /* Prefix Options */ u_char prefix_options; /* Associated Area */ u_int32_t area_id; /* Path-type */ u_char type; u_char subtype; /* only used for redistribute i.e ZEBRA_ROUTE_XXX */ /* Cost */ u_int8_t metric_type; u_int32_t cost; u_int32_t cost_e2; }; #define OSPF6_PATH_TYPE_NONE 0 #define OSPF6_PATH_TYPE_INTRA 1 #define OSPF6_PATH_TYPE_INTER 2 #define OSPF6_PATH_TYPE_EXTERNAL1 3 #define OSPF6_PATH_TYPE_EXTERNAL2 4 #define OSPF6_PATH_TYPE_REDISTRIBUTE 5 #define OSPF6_PATH_TYPE_MAX 6 #include "prefix.h" #include "table.h" struct ospf6_route { struct route_node *rnode; struct ospf6_route_table *table; struct ospf6_route *prev; struct ospf6_route *next; unsigned int lock; /* Destination Type */ u_char type; /* Destination ID */ struct prefix prefix; /* Time */ struct timeval installed; struct timeval changed; /* flag */ u_char flag; /* path */ struct ospf6_path path; /* nexthop */ struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; /* route option */ void *route_option; /* link state id for advertising */ u_int32_t linkstate_id; }; #define OSPF6_DEST_TYPE_NONE 0 #define OSPF6_DEST_TYPE_ROUTER 1 #define OSPF6_DEST_TYPE_NETWORK 2 #define OSPF6_DEST_TYPE_DISCARD 3 #define OSPF6_DEST_TYPE_LINKSTATE 4 #define OSPF6_DEST_TYPE_RANGE 5 #define OSPF6_DEST_TYPE_MAX 6 #define OSPF6_ROUTE_CHANGE 0x01 #define OSPF6_ROUTE_ADD 0x02 #define OSPF6_ROUTE_REMOVE 0x04 #define OSPF6_ROUTE_BEST 0x08 #define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10 #define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20 #define OSPF6_ROUTE_WAS_REMOVED 0x40 struct ospf6_route_table { 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) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) #define ospf6_linkstate_prefix_id(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) #define ADV_ROUTER_IN_PREFIX(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) #define ID_IN_PREFIX(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) /* Function prototype */ 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-0.99.22.4/ospf6d/ospf6_snmp.c0000644000175000017500000011221612177450262013675 00000000000000/* 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 "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: return SNMP_INTEGER (100000); 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 ? sizeof 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; u_int32_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; int offsetlen; char a[16], b[16], c[16]; struct ospf6_area *oa; 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) { unsigned int ifindex, instid; 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; ifindex = instid = 0; /* 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) { unsigned int ifindex, 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; ifindex = 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-0.99.22.4/ospf6d/ospf6_snmp.h0000644000175000017500000000206412177450262013701 00000000000000/* 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-0.99.22.4/ospf6d/ospf6_spf.c0000644000175000017500000005007412177450262013513 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* Shortest Path First calculation for OSPFv3 */ #include #include "log.h" #include "memory.h" #include "command.h" #include "vty.h" #include "prefix.h" #include "pqueue.h" #include "linklist.h" #include "thread.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_area.h" #include "ospf6_spf.h" #include "ospf6_intra.h" #include "ospf6_interface.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_spf = 0; 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; struct ospf6_interface *oi; u_int16_t type; u_int32_t adv_router; struct ospf6_lsa *lsa; struct ospf6_link_lsa *link_lsa; char buf[64]; assert (VERTEX_IS_TYPE (ROUTER, w)); ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex : ROUTER_LSDESC_GET_IFID (lsdesc)); oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_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; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) { for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++) { if (ospf6_nexthop_is_set (&route->nexthop[j])) { if (ospf6_nexthop_is_same (&route->nexthop[j], &v->nexthop[i])) break; else continue; } ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]); break; } } prev = (struct ospf6_vertex *) route->route_option; 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; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]); if (v->parent) listnode_add_sort (v->parent->child_list, v); route->route_option = v; ospf6_route_add (route, result_table); return 0; } void ospf6_spf_table_finish (struct ospf6_route_table *result_table) { struct ospf6_route *route; struct ospf6_vertex *v; for (route = ospf6_route_head (result_table); route; route = ospf6_route_next (route)) { v = (struct ospf6_vertex *) route->route_option; ospf6_vertex_delete (v); ospf6_route_remove (route, result_table); } } /* RFC2328 16.1. Calculating the shortest-path tree for an area */ /* RFC2740 3.8.1. Calculating the shortest path tree for an area */ void ospf6_spf_calculation (u_int32_t router_id, struct ospf6_route_table *result_table, struct ospf6_area *oa) { struct pqueue *candidate_list; struct ospf6_vertex *root, *v, *w; int i; int size; caddr_t lsdesc; struct ospf6_lsa *lsa; 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; /* For each LS description in the just-added vertex V's LSA */ size = (VERTEX_IS_TYPE (ROUTER, v) ? sizeof (struct ospf6_router_lsdesc) : sizeof (struct ospf6_network_lsdesc)); for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4; lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size) { lsa = ospf6_lsdesc_lsa (lsdesc, v); if (lsa == NULL) continue; if (! ospf6_lsdesc_backlink (lsa, lsdesc, v)) continue; w = ospf6_vertex_create (lsa); w->area = oa; w->parent = v; if (VERTEX_IS_TYPE (ROUTER, v)) { w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc); w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1); } else /* NETWORK */ { w->cost = v->cost; w->hops = v->hops + 1; } /* nexthop calculation */ if (w->hops == 0) w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc); else if (w->hops == 1 && v->hops == 0) ospf6_nexthop_calc (w, v, lsdesc); else { for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); } /* add new candidate to the candidate_list */ if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_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 timeval start, end, runtime; oa = (struct ospf6_area *) THREAD_ARG (t); oa->thread_spf_calculation = NULL; 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); /* execute SPF calculation */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &start); ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa); quagga_gettime (QUAGGA_CLK_MONOTONIC, &end); timersub (&end, &start, &runtime); if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF runtime: %ld sec %ld usec", runtime.tv_sec, runtime.tv_usec); ospf6_intra_route_calculation (oa); ospf6_intra_brouter_calculation (oa); return 0; } void ospf6_spf_schedule (struct ospf6_area *oa) { if (oa->thread_spf_calculation) return; oa->thread_spf_calculation = thread_add_event (master, ospf6_spf_calculation_thread, oa, 0); } void ospf6_spf_display_subtree (struct vty *vty, 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; } int config_write_ospf6_debug_spf (struct vty *vty) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) vty_out (vty, "debug ospf6 spf process%s", VNL); if (IS_OSPF6_DEBUG_SPF (TIME)) vty_out (vty, "debug ospf6 spf time%s", VNL); if (IS_OSPF6_DEBUG_SPF (DATABASE)) vty_out (vty, "debug ospf6 spf database%s", VNL); return 0; } void install_element_ospf6_debug_spf (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) { } quagga-0.99.22.4/ospf6d/ospf6_spf.h0000644000175000017500000000526112000052240013471 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_SPF_H #define OSPF6_SPF_H /* Debug option */ extern unsigned char conf_debug_ospf6_spf; #define OSPF6_DEBUG_SPF_PROCESS 0x01 #define OSPF6_DEBUG_SPF_TIME 0x02 #define OSPF6_DEBUG_SPF_DATABASE 0x04 #define OSPF6_DEBUG_SPF_ON(level) \ (conf_debug_ospf6_spf |= (level)) #define OSPF6_DEBUG_SPF_OFF(level) \ (conf_debug_ospf6_spf &= ~(level)) #define IS_OSPF6_DEBUG_SPF(level) \ (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_ ## level) /* Transit Vertex */ struct ospf6_vertex { /* type of this vertex */ u_int8_t type; /* Vertex Identifier */ struct prefix vertex_id; /* Identifier String */ char name[128]; /* Associated Area */ struct ospf6_area *area; /* Associated LSA */ struct ospf6_lsa *lsa; /* Distance from Root (i.e. Cost) */ u_int32_t cost; /* Router hops to this node */ u_char hops; /* nexthops to this node */ struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; /* capability bits */ u_char capability; /* Optional capabilities */ u_char options[3]; /* For tree display */ struct ospf6_vertex *parent; 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) 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_area *oa); extern void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v); extern int config_write_ospf6_debug_spf (struct vty *vty); extern void install_element_ospf6_debug_spf (void); extern void ospf6_spf_init (void); #endif /* OSPF6_SPF_H */ quagga-0.99.22.4/ospf6d/ospf6_top.c0000644000175000017500000004312312132522417013513 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "vty.h" #include "linklist.h" #include "prefix.h" #include "table.h" #include "thread.h" #include "command.h" #include "ospf6_proto.h" #include "ospf6_message.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_zebra.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_flood.h" #include "ospf6_asbr.h" #include "ospf6_abr.h" #include "ospf6_intra.h" #include "ospf6d.h" /* global ospf6d variable */ struct ospf6 *ospf6; 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->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 (); 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); XFREE (MTYPE_OSPF6_TOP, o); } static void 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); ospf6_lsdb_remove_all (o->lsdb); ospf6_route_remove_all (o->route_table); ospf6_route_remove_all (o->brouter_table); } } 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; 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; return 0; } } } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) OSPF6_LSDB_MAXAGE_REMOVER (oi->lsdb); OSPF6_LSDB_MAXAGE_REMOVER (oa->lsdb); } OSPF6_LSDB_MAXAGE_REMOVER (o->lsdb); return 0; } void ospf6_maxage_remove (struct ospf6 *o) { if (o && ! o->maxage_remover) o->maxage_remover = thread_add_event (master, ospf6_maxage_remover, o, 0); } /* start ospf6 */ DEFUN (router_ospf6, router_ospf6_cmd, "router ospf6", ROUTER_STR OSPF6_STR) { if (ospf6 == NULL) ospf6 = ospf6_create (); if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) ospf6_enable (ospf6); /* set current ospf point. */ vty->node = OSPF6_NODE; vty->index = ospf6; return CMD_SUCCESS; } /* stop ospf6 */ DEFUN (no_router_ospf6, no_router_ospf6_cmd, "no router ospf6", NO_STR OSPF6_ROUTER_STR) { if (ospf6 == NULL || CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) vty_out (vty, "OSPFv3 is not running%s", VNL); else ospf6_disable (ospf6); /* return to config node . */ vty->node = CONFIG_NODE; vty->index = NULL; return CMD_SUCCESS; } /* change Router_ID commands. */ DEFUN (ospf6_router_id, ospf6_router_id_cmd, "router-id A.B.C.D", "Configure OSPF Router-ID\n" V4NOTATION_STR) { int ret; u_int32_t router_id; struct ospf6 *o; o = (struct ospf6 *) vty->index; ret = inet_pton (AF_INET, argv[0], &router_id); if (ret == 0) { vty_out (vty, "malformed OSPF Router-ID: %s%s", argv[0], VNL); return CMD_SUCCESS; } o->router_id_static = router_id; if (o->router_id == 0) o->router_id = router_id; return CMD_SUCCESS; } DEFUN (ospf6_interface_area, ospf6_interface_area_cmd, "interface IFNAME area A.B.C.D", "Enable routing on an IPv6 interface\n" IFNAME_STR "Specify the OSPF6 area ID\n" "OSPF6 area ID in IPv4 address notation\n" ) { struct ospf6 *o; struct ospf6_area *oa; struct ospf6_interface *oi; struct interface *ifp; u_int32_t area_id; o = (struct ospf6 *) vty->index; /* find/create ospf6 interface */ ifp = if_get_by_name (argv[0]); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); if (oi->area) { vty_out (vty, "%s already attached to Area %s%s", oi->interface->name, oi->area->name, VNL); return CMD_SUCCESS; } /* parse Area-ID */ if (inet_pton (AF_INET, argv[1], &area_id) != 1) { vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } /* find/create ospf6 area */ oa = ospf6_area_lookup (area_id, o); if (oa == NULL) oa = ospf6_area_create (area_id, o); /* attach interface to area */ listnode_add (oa->if_list, oi); /* sort ?? */ oi->area = oa; SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); /* start up */ thread_add_event (master, interface_up, oi, 0); /* If the router is ABR, originate summary routes */ if (ospf6_is_router_abr (o)) ospf6_abr_enable_area (oa); return CMD_SUCCESS; } DEFUN (no_ospf6_interface_area, no_ospf6_interface_area_cmd, "no interface IFNAME area A.B.C.D", NO_STR "Disable routing on an IPv6 interface\n" IFNAME_STR "Specify the OSPF6 area ID\n" "OSPF6 area ID in IPv4 address notation\n" ) { struct ospf6 *o; struct ospf6_interface *oi; struct ospf6_area *oa; struct interface *ifp; u_int32_t area_id; o = (struct ospf6 *) vty->index; ifp = if_lookup_by_name (argv[0]); if (ifp == NULL) { vty_out (vty, "No such interface %s%s", argv[0], VNL); return CMD_SUCCESS; } oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) { vty_out (vty, "Interface %s not enabled%s", ifp->name, VNL); return CMD_SUCCESS; } /* parse Area-ID */ if (inet_pton (AF_INET, argv[1], &area_id) != 1) { vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } /* 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; } 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; /* 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 */ /* LSAs */ vty_out (vty, " Number of AS scoped LSAs is %u%s", o->lsdb->count, VNL); /* Areas */ vty_out (vty, " Number of areas in this router is %u%s", listcount (o->area_list), VNL); for (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_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; /* 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_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_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } /* 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; if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)) 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); ospf6_redistribute_config_write (vty); ospf6_area_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 (ENABLE_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_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_detail_cmd); install_default (OSPF6_NODE); install_element (OSPF6_NODE, &ospf6_router_id_cmd); install_element (OSPF6_NODE, &ospf6_interface_area_cmd); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd); } quagga-0.99.22.4/ospf6d/ospf6_top.h0000644000175000017500000000351412045513244013521 00000000000000/* * 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; /* AS scope link state database */ struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; struct ospf6_route_table *route_table; struct ospf6_route_table *brouter_table; struct ospf6_route_table *external_table; struct route_table *external_id_table; u_int32_t external_id; /* redistribute route-map */ struct { char *name; struct route_map *map; } rmap[ZEBRA_ROUTE_MAX]; u_char flag; struct thread *maxage_remover; }; #define OSPF6_DISABLED 0x01 /* global pointer for OSPF top data structure */ extern struct ospf6 *ospf6; /* prototypes */ 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-0.99.22.4/ospf6d/ospf6_zebra.c0000644000175000017500000004417312101110036014004 00000000000000/* * 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) { 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 (zclient->redist[type]) return; zclient->redist[type] = 1; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); } void ospf6_zebra_no_redistribute (int type) { if (! zclient->redist[type]) return; zclient->redist[type] = 0; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); } /* Inteface addition message from zebra. */ static int ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_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) { struct interface *ifp; if (!(ifp = zebra_interface_state_read(zclient->ibuf))) 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); #if 0 /* Why is this commented out? */ ospf6_interface_if_del (ifp); #endif /*0*/ ifp->ifindex = IFINDEX_INTERNAL; return 0; } static int ospf6_zebra_if_state_update (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_state_read (zclient->ibuf); if (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", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); ospf6_interface_state_update (ifp); return 0; } static int ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; char buf[128]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); 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_connected_route_update (c->ifp); return 0; } static int ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; char buf[128]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); 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); return 0; } static int ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct prefix_ipv6 p; struct in6_addr *nexthop; s = zclient->ibuf; ifindex = 0; nexthop = NULL; memset (&api, 0, sizeof (api)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop = (struct in6_addr *) malloc (api.nexthop_num * sizeof (struct in6_addr)); stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) { char prefixstr[128], nexthopstr[128]; prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); if (nexthop) inet_ntop (AF_INET6, nexthop, nexthopstr, sizeof (nexthopstr)); else snprintf (nexthopstr, sizeof (nexthopstr), "::"); zlog_debug ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld", (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"), zebra_route_string(api.type), prefixstr, nexthopstr, ifindex); } if (command == ZEBRA_IPV6_ROUTE_ADD) ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, api.nexthop_num, nexthop); else ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) free (nexthop); return 0; } DEFUN (show_zebra, show_zebra_cmd, "show zebra", SHOW_STR "Zebra information\n") { int i; if (zclient == NULL) { vty_out (vty, "Not connected to zebra%s", VNL); return CMD_SUCCESS; } vty_out (vty, "Zebra Infomation%s", VNL); vty_out (vty, " enable: %d fail: %d%s", zclient->enable, zclient->fail, VNL); vty_out (vty, " redistribute default: %d%s", zclient->redist_default, VNL); vty_out (vty, " redistribute:"); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (zclient->redist[i]) vty_out (vty, " %s", zebra_route_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 (! zclient->redist[ZEBRA_ROUTE_OSPF6]) { vty_out (vty, "router zebra%s", VNL); vty_out (vty, " no redistribute ospf6%s", VNL); vty_out (vty, "!%s", VNL); } return 0; } /* Zebra node structure. */ 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; unsigned int *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)) { char ifname[IFNAMSIZ]; inet_ntop (AF_INET6, &request->nexthop[i].address, buf, sizeof (buf)); if (!if_indextoname(request->nexthop[i].ifindex, ifname)) strlcpy(ifname, "unknown", sizeof(ifname)); 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.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); 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 (! zclient->redist[ZEBRA_ROUTE_OSPF6]) { ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; return; } ospf6_zebra_route_update (ADD, request); } void ospf6_zebra_route_update_remove (struct ospf6_route *request) { if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) { ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; return; } ospf6_zebra_route_update (REM, request); } DEFUN (redistribute_ospf6, redistribute_ospf6_cmd, "redistribute ospf6", "Redistribute control\n" "OSPF6 route\n") { struct ospf6_route *route; if (zclient->redist[ZEBRA_ROUTE_OSPF6]) return CMD_SUCCESS; zclient->redist[ZEBRA_ROUTE_OSPF6] = 1; if (ospf6 == NULL) return CMD_SUCCESS; /* send ospf6 route to zebra route table */ for (route = ospf6_route_head (ospf6->route_table); route; route = ospf6_route_next (route)) ospf6_zebra_route_update_add (route); ospf6->route_table->hook_add = ospf6_zebra_route_update_add; ospf6->route_table->hook_remove = ospf6_zebra_route_update_remove; return CMD_SUCCESS; } DEFUN (no_redistribute_ospf6, no_redistribute_ospf6_cmd, "no redistribute ospf6", NO_STR "Redistribute control\n" "OSPF6 route\n") { struct ospf6_route *route; if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) return CMD_SUCCESS; zclient->redist[ZEBRA_ROUTE_OSPF6] = 0; if (ospf6 == NULL) return CMD_SUCCESS; ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; /* withdraw ospf6 route from zebra route table */ for (route = ospf6_route_head (ospf6->route_table); route; route = ospf6_route_next (route)) ospf6_zebra_route_update_remove (route); return CMD_SUCCESS; } void ospf6_zebra_init (void) { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_OSPF6); 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 (ENABLE_NODE, &show_zebra_cmd); install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); install_default (ZEBRA_NODE); install_element (ZEBRA_NODE, &redistribute_ospf6_cmd); install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd); return; } /* Debug */ DEFUN (debug_ospf6_zebra_sendrecv, debug_ospf6_zebra_sendrecv_cmd, "debug ospf6 zebra (send|recv)", DEBUG_STR OSPF6_STR "Debug connection between zebra\n" "Debug Sending zebra\n" "Debug Receiving zebra\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_ZEBRA_SEND; else if (! strncmp (argv[0], "r", 1)) level = OSPF6_DEBUG_ZEBRA_RECV; } else level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; OSPF6_DEBUG_ZEBRA_ON (level); return CMD_SUCCESS; } ALIAS (debug_ospf6_zebra_sendrecv, debug_ospf6_zebra_cmd, "debug ospf6 zebra", DEBUG_STR OSPF6_STR "Debug connection between zebra\n" ) DEFUN (no_debug_ospf6_zebra_sendrecv, no_debug_ospf6_zebra_sendrecv_cmd, "no debug ospf6 zebra (send|recv)", NO_STR DEBUG_STR OSPF6_STR "Debug connection between zebra\n" "Debug Sending zebra\n" "Debug Receiving zebra\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_ZEBRA_SEND; else if (! strncmp (argv[0], "r", 1)) level = OSPF6_DEBUG_ZEBRA_RECV; } else level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; OSPF6_DEBUG_ZEBRA_OFF (level); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_zebra_sendrecv, no_debug_ospf6_zebra_cmd, "no debug ospf6 zebra", NO_STR DEBUG_STR OSPF6_STR "Debug connection between zebra\n" ) int config_write_ospf6_debug_zebra (struct vty *vty) { if (IS_OSPF6_DEBUG_ZEBRA (SEND) && IS_OSPF6_DEBUG_ZEBRA (RECV)) vty_out (vty, "debug ospf6 zebra%s", VNL); else { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) vty_out (vty, "debug ospf6 zebra send%s", VNL); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) vty_out (vty, "debug ospf6 zebra recv%s", VNL); } return 0; } void install_element_ospf6_debug_zebra (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-0.99.22.4/ospf6d/ospf6_zebra.h0000644000175000017500000000334612000052240014006 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_ZEBRA_H #define OSPF6_ZEBRA_H #include "zclient.h" /* Debug option */ extern unsigned char conf_debug_ospf6_zebra; #define OSPF6_DEBUG_ZEBRA_SEND 0x01 #define OSPF6_DEBUG_ZEBRA_RECV 0x02 #define OSPF6_DEBUG_ZEBRA_ON(level) \ (conf_debug_ospf6_zebra |= level) #define OSPF6_DEBUG_ZEBRA_OFF(level) \ (conf_debug_ospf6_zebra &= ~(level)) #define IS_OSPF6_DEBUG_ZEBRA(e) \ (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e) extern struct zclient *zclient; 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) (zclient->redist[type]) extern void ospf6_zebra_init (void); extern int config_write_ospf6_debug_zebra (struct vty *vty); extern void install_element_ospf6_debug_zebra (void); #endif /*OSPF6_ZEBRA_H*/ quagga-0.99.22.4/ospf6d/ospf6d.c0000644000175000017500000015662512132522417013011 00000000000000/* * 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; 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; /* 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 (); 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 (VIEW_NODE, &show_version_ospf6_cmd); install_element (ENABLE_NODE, &show_version_ospf6_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_router_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_network_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); #define INSTALL(n,c) \ install_element (n ## _NODE, &show_ipv6_ospf6_ ## c) INSTALL (VIEW, database_cmd); INSTALL (VIEW, database_detail_cmd); INSTALL (VIEW, database_type_cmd); INSTALL (VIEW, database_type_detail_cmd); INSTALL (VIEW, database_id_cmd); INSTALL (VIEW, database_id_detail_cmd); INSTALL (VIEW, database_linkstate_id_cmd); INSTALL (VIEW, database_linkstate_id_detail_cmd); INSTALL (VIEW, database_router_cmd); INSTALL (VIEW, database_router_detail_cmd); INSTALL (VIEW, database_adv_router_cmd); INSTALL (VIEW, database_adv_router_detail_cmd); INSTALL (VIEW, database_type_id_cmd); INSTALL (VIEW, database_type_id_detail_cmd); INSTALL (VIEW, database_type_linkstate_id_cmd); INSTALL (VIEW, database_type_linkstate_id_detail_cmd); INSTALL (VIEW, database_type_router_cmd); INSTALL (VIEW, database_type_router_detail_cmd); INSTALL (VIEW, database_type_adv_router_cmd); INSTALL (VIEW, database_type_adv_router_detail_cmd); INSTALL (VIEW, database_adv_router_linkstate_id_cmd); INSTALL (VIEW, database_adv_router_linkstate_id_detail_cmd); INSTALL (VIEW, database_id_router_cmd); INSTALL (VIEW, database_id_router_detail_cmd); INSTALL (VIEW, database_type_id_router_cmd); INSTALL (VIEW, database_type_id_router_detail_cmd); INSTALL (VIEW, database_type_adv_router_linkstate_id_cmd); INSTALL (VIEW, database_type_adv_router_linkstate_id_detail_cmd); INSTALL (VIEW, database_self_originated_cmd); INSTALL (VIEW, database_self_originated_detail_cmd); INSTALL (VIEW, database_type_self_originated_cmd); INSTALL (VIEW, database_type_self_originated_detail_cmd); INSTALL (VIEW, database_type_id_self_originated_cmd); INSTALL (VIEW, database_type_id_self_originated_detail_cmd); INSTALL (VIEW, database_type_self_originated_linkstate_id_cmd); INSTALL (VIEW, database_type_self_originated_linkstate_id_detail_cmd); INSTALL (ENABLE, database_cmd); INSTALL (ENABLE, database_detail_cmd); INSTALL (ENABLE, database_type_cmd); INSTALL (ENABLE, database_type_detail_cmd); INSTALL (ENABLE, database_id_cmd); INSTALL (ENABLE, database_id_detail_cmd); INSTALL (ENABLE, database_linkstate_id_cmd); INSTALL (ENABLE, database_linkstate_id_detail_cmd); INSTALL (ENABLE, database_router_cmd); INSTALL (ENABLE, database_router_detail_cmd); INSTALL (ENABLE, database_adv_router_cmd); INSTALL (ENABLE, database_adv_router_detail_cmd); INSTALL (ENABLE, database_type_id_cmd); INSTALL (ENABLE, database_type_id_detail_cmd); INSTALL (ENABLE, database_type_linkstate_id_cmd); INSTALL (ENABLE, database_type_linkstate_id_detail_cmd); INSTALL (ENABLE, database_type_router_cmd); INSTALL (ENABLE, database_type_router_detail_cmd); INSTALL (ENABLE, database_type_adv_router_cmd); INSTALL (ENABLE, database_type_adv_router_detail_cmd); INSTALL (ENABLE, database_adv_router_linkstate_id_cmd); INSTALL (ENABLE, database_adv_router_linkstate_id_detail_cmd); INSTALL (ENABLE, database_id_router_cmd); INSTALL (ENABLE, database_id_router_detail_cmd); INSTALL (ENABLE, database_type_id_router_cmd); INSTALL (ENABLE, database_type_id_router_detail_cmd); INSTALL (ENABLE, database_type_adv_router_linkstate_id_cmd); INSTALL (ENABLE, database_type_adv_router_linkstate_id_detail_cmd); INSTALL (ENABLE, database_self_originated_cmd); INSTALL (ENABLE, database_self_originated_detail_cmd); INSTALL (ENABLE, database_type_self_originated_cmd); INSTALL (ENABLE, database_type_self_originated_detail_cmd); INSTALL (ENABLE, database_type_id_self_originated_cmd); INSTALL (ENABLE, database_type_id_self_originated_detail_cmd); INSTALL (ENABLE, database_type_self_originated_linkstate_id_cmd); INSTALL (ENABLE, database_type_self_originated_linkstate_id_detail_cmd); /* Make ospf protocol socket. */ ospf6_serv_sock (); thread_add_read (master, ospf6_receive, NULL, ospf6_sock); } void ospf6_clean (void) { if (ospf6->route_table) ospf6_route_remove_all (ospf6->route_table); if (ospf6->brouter_table) ospf6_route_remove_all (ospf6->brouter_table); } quagga-0.99.22.4/ospf6d/ospf6d.conf.sample0000644000175000017500000000212612000052240014740 00000000000000! ! 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-0.99.22.4/ospf6d/ospf6d.h0000644000175000017500000001053312051607643013006 00000000000000/* * 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" /* global variables */ extern struct thread_master *master; #ifdef INRIA_IPV6 #ifndef IPV6_PKTINFO #define IPV6_PKTINFO IPV6_RECVPKTINFO #endif /* IPV6_PKTINFO */ #endif /* INRIA_IPV6 */ /* Historical for KAME. */ #ifndef IPV6_JOIN_GROUP #ifdef IPV6_ADD_MEMBERSHIP #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif /* IPV6_ADD_MEMBERSHIP. */ #ifdef IPV6_JOIN_MEMBERSHIP #define IPV6_JOIN_GROUP IPV6_JOIN_MEMBERSHIP #endif /* IPV6_JOIN_MEMBERSHIP. */ #endif /* ! IPV6_JOIN_GROUP*/ #ifndef IPV6_LEAVE_GROUP #ifdef IPV6_DROP_MEMBERSHIP #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif /* IPV6_DROP_MEMBERSHIP */ #endif /* ! IPV6_LEAVE_GROUP */ #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, "%ldd%02ld:%02ld:%02ld", \ (tv)->tv_sec / 60 / 60 / 24, \ (tv)->tv_sec / 60 / 60 % 24, \ (tv)->tv_sec / 60 % 60, \ (tv)->tv_sec % 60); \ else \ snprintf (buf, size, "%02ld:%02ld:%02ld", \ (tv)->tv_sec / 60 / 60 % 24, \ (tv)->tv_sec / 60 % 60, \ (tv)->tv_sec % 60); \ } while (0) #define timerstring_local(tv, buf, size) \ do { \ int ret; \ struct tm *tm; \ tm = localtime (&(tv)->tv_sec); \ ret = strftime (buf, size, "%Y/%m/%d %H:%M:%S", tm); \ if (ret == 0) \ zlog_warn ("strftime error"); \ } while (0) /* for commands */ #define OSPF6_AREA_STR "Area information\n" #define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n" #define OSPF6_SPF_STR "Shortest Path First tree information\n" #define OSPF6_ROUTER_ID_STR "Specify Router-ID\n" #define OSPF6_LS_ID_STR "Specify Link State ID\n" #define VNL VTY_NEWLINE #define OSPF6_CMD_CHECK_RUNNING() \ if (ospf6 == NULL) \ { \ vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \ return CMD_SUCCESS; \ } /* Function Prototypes */ extern struct route_node *route_prev (struct route_node *node); extern void ospf6_debug (void); extern void ospf6_init (void); #endif /* OSPF6D_H */ quagga-0.99.22.4/ospfclient/0000755000175000017500000000000012211704577012461 500000000000000quagga-0.99.22.4/ospfclient/AUTHORS0000644000175000017500000000004512000052240013423 00000000000000Ralph Keller quagga-0.99.22.4/ospfclient/COPYING0000644000175000017500000004307612000052240013421 00000000000000 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-0.99.22.4/ospfclient/INSTALL0000644000175000017500000001722712000052240013416 00000000000000Basic 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-0.99.22.4/ospfclient/Makefile.am0000644000175000017500000000113312177450262014433 00000000000000## Automake.am for OSPF API client INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 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) $(PICFLAGS) ospfclient_LDFLAGS = $(AM_LDFLAGS) $(PILDFLAGS) quagga-0.99.22.4/ospfclient/Makefile.in0000644000175000017500000006223212211704502014437 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = README $(ospfapiheader_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(top_srcdir)/depcomp AUTHORS COPYING \ INSTALL NEWS 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) 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_LIBADD = am_libospfapiclient_la_OBJECTS = ospf_apiclient.lo libospfapiclient_la_OBJECTS = $(am_libospfapiclient_la_OBJECTS) libospfapiclient_la_LINK = $(LIBTOOL) --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) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ospfclient_CFLAGS) \ $(CFLAGS) $(ospfclient_LDFLAGS) $(LDFLAGS) -o $@ 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 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) $(PICFLAGS) ospfclient_LDFLAGS = $(AM_LDFLAGS) $(PILDFLAGS) 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 .PRECIOUS: 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) $(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) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< ospfclient-ospfclient.o: ospfclient.c @am__fastdepCC_TRUE@ $(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__mv) $(DEPDIR)/ospfclient-ospfclient.Tpo $(DEPDIR)/ospfclient-ospfclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ospfclient.c' object='ospfclient-ospfclient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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@ $(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__mv) $(DEPDIR)/ospfclient-ospfclient.Tpo $(DEPDIR)/ospfclient-ospfclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ospfclient.c' object='ospfclient-ospfclient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-libLTLIBRARIES \ uninstall-ospfapiheaderHEADERS uninstall-sbinPROGRAMS # 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-0.99.22.4/ospfclient/NEWS0000644000175000017500000000003112000052240013045 00000000000000This file contains news. quagga-0.99.22.4/ospfclient/README0000644000175000017500000000014112000052240013230 00000000000000For more information about this software check out: http://www.tik.ee.ethz.ch/~keller/ospfapi/ quagga-0.99.22.4/ospfclient/ospf_apiclient.c0000644000175000017500000004613012166576100015546 00000000000000/* * 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-0.99.22.4/ospfclient/ospf_apiclient.h0000644000175000017500000001101512000052240015522 00000000000000/* * 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 0 /* 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-0.99.22.4/ospfclient/ospfclient.c0000644000175000017500000002135112000052240014670 00000000000000/* * 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[]) { struct thread thread; 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 */ while (1) { thread_fetch (master, &thread); thread_call (&thread); } /* Never reached */ return 0; } quagga-0.99.22.4/ospfd/0000755000175000017500000000000012211704577011426 500000000000000quagga-0.99.22.4/ospfd/ChangeLog.opaque.txt0000644000175000017500000002305012000052240015202 00000000000000----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- 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-0.99.22.4/ospfd/Makefile.am0000644000175000017500000000241212177450262013401 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 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_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_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt examplesdir = $(exampledir) dist_examples_DATA = ospfd.conf.sample quagga-0.99.22.4/ospfd/Makefile.in0000644000175000017500000006520112211704502013403 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(ospfdheader_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(top_srcdir)/depcomp 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) 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_LIBADD = 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_vty.lo ospf_api.lo \ ospf_apiserver.lo libospf_la_OBJECTS = $(am_libospf_la_OBJECTS) libospf_la_LINK = $(LIBTOOL) --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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 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_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_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ 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 .PRECIOUS: 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) $(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) $(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_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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-libLTLIBRARIES uninstall-ospfdheaderHEADERS \ uninstall-sbinPROGRAMS # 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-0.99.22.4/ospfd/OSPF-MIB.txt0000644000175000017500000025014412000052240013244 00000000000000OSPF-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-0.99.22.4/ospfd/OSPF-TRAP-MIB.txt0000644000175000017500000003733712000052240014017 00000000000000OSPF-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-0.99.22.4/ospfd/ospf_abr.c0000644000175000017500000014531512177450262013316 00000000000000/* * 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); 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-0.99.22.4/ospfd/ospf_abr.h0000644000175000017500000000563212000052240013273 00000000000000/* * 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-0.99.22.4/ospfd/ospf_api.c0000644000175000017500000003714312211105060013300 00000000000000/* * 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 #ifndef HAVE_OPAQUE_LSA #error "Core Opaque-LSA module must be configured." #endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "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; int 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; int 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; int 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; int 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-0.99.22.4/ospfd/ospf_api.h0000644000175000017500000002511712000052240013300 00000000000000/* * 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-0.99.22.4/ospfd/ospf_apiserver.c0000644000175000017500000020440212177450262014543 00000000000000/* * 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 #ifndef HAVE_OPAQUE_LSA #error "Core Opaque-LSA module must be configured." #endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "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", 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", 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)", 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)", 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, 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, 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-0.99.22.4/ospfd/ospf_apiserver.h0000644000175000017500000001761112132522417014545 00000000000000/* * 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-0.99.22.4/ospfd/ospf_asbr.c0000644000175000017500000001565412101110036013456 00000000000000/* * 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, unsigned int ifindex, struct in_addr nexthop) { struct external_info *new; struct route_node *rn; /* Initialize route table. */ if (EXTERNAL_INFO (type) == NULL) EXTERNAL_INFO (type) = route_table_init (); rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p); /* If old info exists, -- discard new one or overwrite with new one? */ if (rn) if (rn->info) { route_unlock_node (rn); zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.", 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 = 0; 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); 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-0.99.22.4/ospfd/ospf_asbr.h0000644000175000017500000000530712000052240013455 00000000000000/* * OSPF AS Boundary Router functions. * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ASBR_H #define _ZEBRA_OSPF_ASBR_H struct route_map_set_values { int32_t metric; int32_t metric_type; }; /* Redistributed external information. */ struct external_info { /* Type of source protocol. */ u_char type; /* Prefix. */ struct prefix_ipv4 p; /* Interface index. */ unsigned int ifindex; /* Nexthop address. */ struct in_addr nexthop; /* Additional Route tag. */ u_int32_t tag; struct route_map_set_values route_map_set; #define ROUTEMAP_METRIC(E) (E)->route_map_set.metric #define ROUTEMAP_METRIC_TYPE(E) (E)->route_map_set.metric_type }; #define OSPF_ASBR_CHECK_DELAY 30 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, unsigned int, struct in_addr); 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-0.99.22.4/ospfd/ospf_ase.c0000644000175000017500000005666412132522417013323 00000000000000/* * 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; } 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; ospf = THREAD_ARG (t); ospf->t_ase_calc = NULL; if (ospf->ase_calc) { ospf->ase_calc = 0; /* Calculate external route for each AS-external-LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_ase_calculate_route (ospf, lsa); /* 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 (); } 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(); /* 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_get (top->external_lsas, (struct prefix *) &p); lst = rn->info; /* XXX lst can be NULL */ if (lst) { listnode_delete (lst, lsa); ospf_lsa_unlock (&lsa); /* external_lsas list */ } } 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; } /* install changes to zebra */ ospf_ase_compare_tables (ospf->new_external_route, tmp_old); /* update ospf->old_external_route table */ if (rn && rn->info) ospf_route_free ((struct ospf_route *) rn->info); rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p); /* if new route exists, install it to ospf->old_external_route */ if (rn2 && rn2->info) { if (!rn) rn = route_node_get (ospf->old_external_route, (struct prefix *) &p); rn->info = rn2->info; } else { /* remove route node from ospf->old_external_route */ if (rn) { rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } } if (rn2) { /* rn2->info is stored in route node of ospf->old_external_route */ rn2->info = NULL; route_unlock_node (rn2); route_unlock_node (rn2); } route_table_finish (tmp_old); } quagga-0.99.22.4/ospfd/ospf_ase.h0000644000175000017500000000333212000052240013272 00000000000000/* * 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-0.99.22.4/ospfd/ospf_dump.c0000644000175000017500000013524612045513244013513 00000000000000/* * 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; /* 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; 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; if (!t) return "inactive"; w = d = h = m = s = ms = 0; memset (buf, 0, size); ms = t->tv_usec / 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, t->tv_sec); else if (m) snprintf (buf, size, "%ldm%02lds", m, t->tv_sec); else snprintf (buf, size, "%ld.%03lds", t->tv_sec, ms); 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|*", (options & OSPF_OPTION_O) ? "O" : "-", (options & OSPF_OPTION_DC) ? "DC" : "-", (options & OSPF_OPTION_EA) ? "EA" : "-", (options & OSPF_OPTION_NP) ? "N/P" : "-", (options & OSPF_OPTION_MC) ? "MC" : "-", (options & OSPF_OPTION_E) ? "E" : "-"); return buf; } 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 %d", 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; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_dump (s, length); break; #endif /* HAVE_OPAQUE_LSA */ default: break; } stream_forward_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_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 (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, &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 (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, &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); } quagga-0.99.22.4/ospfd/ospf_dump.h0000644000175000017500000001151412045513244013507 00000000000000/* * OSPFd dump routine. * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_DUMP_H #define _ZEBRA_OSPF_DUMP_H /* Debug Flags. */ #define OSPF_DEBUG_HELLO 0x01 #define OSPF_DEBUG_DB_DESC 0x02 #define OSPF_DEBUG_LS_REQ 0x04 #define OSPF_DEBUG_LS_UPD 0x08 #define OSPF_DEBUG_LS_ACK 0x10 #define OSPF_DEBUG_ALL 0x1f #define OSPF_DEBUG_SEND 0x01 #define OSPF_DEBUG_RECV 0x02 #define OSPF_DEBUG_SEND_RECV 0x03 #define OSPF_DEBUG_DETAIL 0x04 #define OSPF_DEBUG_ISM_STATUS 0x01 #define OSPF_DEBUG_ISM_EVENTS 0x02 #define OSPF_DEBUG_ISM_TIMERS 0x04 #define OSPF_DEBUG_ISM 0x07 #define OSPF_DEBUG_NSM_STATUS 0x01 #define OSPF_DEBUG_NSM_EVENTS 0x02 #define OSPF_DEBUG_NSM_TIMERS 0x04 #define OSPF_DEBUG_NSM 0x07 #define OSPF_DEBUG_LSA_GENERATE 0x01 #define OSPF_DEBUG_LSA_FLOODING 0x02 #define OSPF_DEBUG_LSA_INSTALL 0x04 #define OSPF_DEBUG_LSA_REFRESH 0x08 #define OSPF_DEBUG_LSA 0x0F #define OSPF_DEBUG_ZEBRA_INTERFACE 0x01 #define OSPF_DEBUG_ZEBRA_REDISTRIBUTE 0x02 #define OSPF_DEBUG_ZEBRA 0x03 #define OSPF_DEBUG_EVENT 0x01 #define OSPF_DEBUG_NSSA 0x02 /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) #define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) #define TERM_DEBUG_PACKET_ON(a, b) term_debug_ospf_packet[a] |= (b) #define TERM_DEBUG_PACKET_OFF(a, b) term_debug_ospf_packet[a] &= ~(b) #define DEBUG_PACKET_ON(a, b) \ do { \ CONF_DEBUG_PACKET_ON(a, b); \ TERM_DEBUG_PACKET_ON(a, b); \ } while (0) #define DEBUG_PACKET_OFF(a, b) \ do { \ CONF_DEBUG_PACKET_OFF(a, b); \ TERM_DEBUG_PACKET_OFF(a, b); \ } while (0) #define CONF_DEBUG_ON(a, b) conf_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) #define CONF_DEBUG_OFF(a, b) conf_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) #define TERM_DEBUG_ON(a, b) term_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) #define TERM_DEBUG_OFF(a, b) term_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) #define DEBUG_ON(a, b) \ do { \ CONF_DEBUG_ON(a, b); \ TERM_DEBUG_ON(a, b); \ } while (0) #define DEBUG_OFF(a, b) \ do { \ CONF_DEBUG_OFF(a, b); \ TERM_DEBUG_OFF(a, b); \ } while (0) /* Macro for checking debug option. */ #define IS_DEBUG_OSPF_PACKET(a, b) \ (term_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) #define IS_DEBUG_OSPF(a, b) \ (term_debug_ospf_ ## a & OSPF_DEBUG_ ## b) #define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event,EVENT) #define IS_DEBUG_OSPF_NSSA IS_DEBUG_OSPF(nssa,NSSA) #define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) #define IS_CONF_DEBUG_OSPF(a, b) \ (conf_debug_ospf_ ## a & OSPF_DEBUG_ ## b) #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; /* 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-0.99.22.4/ospfd/ospf_flood.c0000644000175000017500000007626612101110036013640 00000000000000/* * 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: #endif /* HAVE_OPAQUE_LSA */ /* We must find the interface the LSA could belong to. If the interface is no more a broadcast type or we are no more the DR, we flush the LSA otherwise -- create the new instance and schedule flooding. */ /* Look through all interfaces, not just area, since interface could be moved from one area to another. */ for (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; } #ifdef HAVE_OPAQUE_LSA if (new->data->type == OSPF_OPAQUE_LINK_LSA) { ospf_opaque_lsa_refresh (new); return; } #endif /* HAVE_OPAQUE_LSA */ 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; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AREA_LSA: ospf_opaque_lsa_refresh (new); break; case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */ break; #endif /* HAVE_OPAQUE_LSA */ default: break; } } /* OSPF LSA flooding -- RFC2328 Section 13.(5). */ /* Now Updated for NSSA operation, as follows: Type-5's have no change. Blocked to STUB or NSSA. Type-7's can be received, and if a DR they will also flood the local NSSA Area as Type-7's If a Self-Originated LSA (now an ASBR), The LSDB will be updated as Type-5's, (for continual re-fresh) If an NSSA-IR it is installed/flooded as Type-7, P-bit on. if an NSSA-ABR it is installed/flooded as Type-7, P-bit off. Later, during the ABR TASK, if the ABR is the Elected NSSA translator, then All Type-7s (with P-bit ON) are Translated to Type-5's and flooded to all non-NSSA/STUB areas. During ASE Calculations, non-ABRs calculate external routes from Type-7's ABRs calculate external routes from Type-5's and non-self Type-7s */ int ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, struct ospf_lsa *current, struct ospf_lsa *new) { struct ospf_interface *oi; 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), 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), int2tv (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); #ifdef HAVE_OPAQUE_LSA /* Remove the current database copy from all neighbors' Link state retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does ^^^^^^^^^^^^^^^^^^^^^^^ not have area ID. All other (even NSSA's) do have area ID. */ #else /* HAVE_OPAQUE_LSA */ /* Remove the current database copy from all neighbors' Link state retransmission lists. Only AS_EXTERNAL does not have area ID. All other (even NSSA's) do have area ID. */ #endif /* HAVE_OPAQUE_LSA */ if (current) { switch (current->data->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ ospf_ls_retransmit_delete_nbr_as (ospf, current); break; default: ospf_ls_retransmit_delete_nbr_area (nbr->oi->area, current); break; } } /* Do some internal house keeping that is needed here */ SET_FLAG (new->flags, OSPF_LSA_RECEIVED); ospf_lsa_is_self_originated (ospf, new); /* Let it set the flag */ /* Install the new LSA in the link state database (replacing the current database copy). This may cause the routing table calculation to be scheduled. In addition, timestamp the new LSA with the current time. The flooding procedure cannot overwrite the newly installed LSA until MinLSArrival seconds have elapsed. */ 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); } } } #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type)) { if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: Not Opaque-capable."); continue; } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (oi->ospf->opaque) && IS_LSA_SELF (lsa) && onbr->state == NSM_Full) { /* Small attempt to reduce unnecessary retransmission. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: Initial flushing done."); continue; } } #endif /* HAVE_OPAQUE_LSA */ /* 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; #ifdef HAVE_OPAQUE_LSA if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi)) { /* * Link local scoped Opaque-LSA should only be flooded * for the link on which the LSA has received. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi); continue; } #endif /* HAVE_OPAQUE_LSA */ if (ospf_flood_through_interface (oi, inbr, lsa)) lsa_ack_flag = 1; } return (lsa_ack_flag); } int ospf_flood_through_as (struct ospf *ospf, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ case OSPF_OPAQUE_AREA_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* 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 */ #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_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) { lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); ospf_flood_through_area (area, NULL, lsa); ospf_lsa_maxage (area->ospf, lsa); } void ospf_lsa_flush_as (struct ospf *ospf, struct ospf_lsa *lsa) { lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); ospf_flood_through_as (ospf, NULL, lsa); ospf_lsa_maxage (ospf, lsa); } 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: #endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_area (lsa, lsa->area); break; case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_as (ospf, lsa); break; default: zlog_info ("%s: Unknown LSA type %u", __func__, lsa->data->type); break; } } quagga-0.99.22.4/ospfd/ospf_flood.h0000644000175000017500000000627412045513244013654 00000000000000/* * 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-0.99.22.4/ospfd/ospf_ia.c0000644000175000017500000004704412000052240013116 00000000000000/* * 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-0.99.22.4/ospfd/ospf_ia.h0000644000175000017500000000273712000052240013123 00000000000000/* * 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-0.99.22.4/ospfd/ospf_interface.c0000644000175000017500000007553612177450262014521 00000000000000/* * 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; } /* 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); /* Add pseudo neighbor. */ oi->nbr_self = ospf_nbr_new (oi); oi->ls_upd_queue = route_table_init (); oi->t_ls_upd_event = NULL; oi->t_ls_ack_direct = NULL; oi->crypt_seqnum = time (NULL); #ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_init (oi); #endif /* HAVE_OPAQUE_LSA */ oi->ospf = ospf; return oi; } /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup (struct ospf_interface *oi) { struct route_node *rn; 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_delete (oi->nbr_self); oi->nbr_self = ospf_nbr_new (oi); ospf_nbr_add_self (oi); } void ospf_if_free (struct ospf_interface *oi) { ospf_if_down (oi); assert (oi->state == ISM_Down); #ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_term (oi); #endif /* HAVE_OPAQUE_LSA */ /* Free Pseudo Neighbour */ ospf_nbr_delete (oi->nbr_self); route_table_finish (oi->nbrs); route_table_finish (oi->ls_upd_queue); /* Free any lists that should be freed */ list_free (oi->nbr_nbma); list_free (oi->ls_ack); list_free (oi->ls_ack_direct.ls_ack); ospf_delete_from_if (oi->ifp, oi); listnode_delete (oi->ospf->oiflist, oi); listnode_delete (oi->area->oiflist, oi); 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; #ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_new_if (ifp); #endif /* HAVE_OPAQUE_LSA */ return rc; } static int ospf_if_delete_hook (struct interface *ifp) { int rc = 0; struct route_node *rn; #ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_del_if (ifp); #endif /* HAVE_OPAQUE_LSA */ 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))); 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"); ospf_nbr_add_self (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; 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. */ if_init (); om->iflist = iflist; if_add_hook (IF_NEW_HOOK, ospf_if_new_hook); if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook); } quagga-0.99.22.4/ospfd/ospf_interface.h0000644000175000017500000002663112177450262014516 00000000000000/* * 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) #define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) #define OSPF_IF_PARAM(O, P) \ (OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\ (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P) #define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1 #define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0 #define SET_IF_PARAM(S, P) ((S)->P##__config) = 1 struct ospf_if_params { DECLARE_IF_PARAM (u_int32_t, transmit_delay); /* Interface Transmisson Delay */ DECLARE_IF_PARAM (u_int32_t, output_cost_cmd);/* Command Interface Output Cost */ DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */ DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to join multicast groups) */ DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ DECLARE_IF_PARAM (u_char, type); /* type of interface */ #define OSPF_IF_ACTIVE 0 #define OSPF_IF_PASSIVE 1 #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; #define OSPF_IFTYPE_NONE 0 #define OSPF_IFTYPE_POINTOPOINT 1 #define OSPF_IFTYPE_BROADCAST 2 #define OSPF_IFTYPE_NBMA 3 #define OSPF_IFTYPE_POINTOMULTIPOINT 4 #define OSPF_IFTYPE_VIRTUALLINK 5 #define OSPF_IFTYPE_LOOPBACK 6 #define OSPF_IFTYPE_MAX 7 /* State of Interface State Machine. */ u_char state; /* 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. */ #ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-9 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ 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 */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ int on_write_q; /* Statistics fields. */ u_int32_t hello_in; /* Hello message input count. */ u_int32_t hello_out; /* Hello message output count. */ u_int32_t db_desc_in; /* database desc. message input count. */ u_int32_t db_desc_out; /* database desc. message output count. */ u_int32_t ls_req_in; /* LS request message input count. */ u_int32_t ls_req_out; /* LS request message output count. */ u_int32_t ls_upd_in; /* LS update message input count. */ u_int32_t ls_upd_out; /* LS update message output count. */ u_int32_t ls_ack_in; /* LS Ack message input count. */ u_int32_t ls_ack_out; /* LS Ack message output count. */ u_int32_t discarded; /* discarded input count by error. */ u_int32_t state_change; /* Number of status change. */ u_int32_t full_nbrs; }; /* Prototypes. */ 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 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-0.99.22.4/ospfd/ospf_ism.c0000644000175000017500000004423012177450262013334 00000000000000/* * 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; } #ifdef HAVE_OPAQUE_LSA ospf_opaque_ism_change (oi, old_state); #endif /* HAVE_OPAQUE_LSA */ /* Check area border status. */ ospf_check_abr_status (oi->ospf); } /* Execute ISM event process. */ int ospf_ism_event (struct thread *thread) { int event; int next_state; struct ospf_interface *oi; oi = THREAD_ARG (thread); event = THREAD_VAL (thread); /* Call function. */ next_state = (*(ISM [oi->state][event].func))(oi); if (! next_state) next_state = ISM [oi->state][event].next_state; if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog (NULL, LOG_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-0.99.22.4/ospfd/ospf_ism.h0000644000175000017500000001026512000052240013315 00000000000000/* * 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-0.99.22.4/ospfd/ospf_lsa.c0000644000175000017500000031155512211704467013330 00000000000000/* * 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" u_int32_t get_metric (u_char *metric) { u_int32_t m; m = metric[0]; m = (m << 8) + metric[1]; m = (m << 8) + metric[2]; return m; } struct timeval tv_adjust (struct timeval a) { while (a.tv_usec >= 1000000) { a.tv_usec -= 1000000; a.tv_sec++; } while (a.tv_usec < 0) { a.tv_usec += 1000000; a.tv_sec--; } return a; } int tv_ceil (struct timeval a) { a = tv_adjust (a); return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec); } int tv_floor (struct timeval a) { a = tv_adjust (a); return a.tv_sec; } struct timeval int2tv (int a) { struct timeval ret; ret.tv_sec = a; ret.tv_usec = 0; return ret; } struct timeval tv_add (struct timeval a, struct timeval b) { struct timeval ret; ret.tv_sec = a.tv_sec + b.tv_sec; ret.tv_usec = a.tv_usec + b.tv_usec; return tv_adjust (ret); } struct timeval tv_sub (struct timeval a, struct timeval b) { struct timeval ret; ret.tv_sec = a.tv_sec - b.tv_sec; ret.tv_usec = a.tv_usec - b.tv_usec; return tv_adjust (ret); } int tv_cmp (struct timeval a, struct timeval b) { return (a.tv_sec == b.tv_sec ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); } int ospf_lsa_refresh_delay (struct ospf_lsa *lsa) { struct timeval delta, now; int delay = 0; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); delta = tv_sub (now, lsa->tv_orig); if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) { delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta)); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_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)", lsa, new); return new; } /* Free OSPF LSA. */ void ospf_lsa_free (struct ospf_lsa *lsa) { assert (lsa->lock == 0); if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("LSA: freed %p", lsa); /* Delete LSA data. */ if (lsa->data != NULL) ospf_lsa_data_free (lsa->data); assert (lsa->refresh_list < 0); memset (lsa, 0, sizeof (struct ospf_lsa)); XFREE (MTYPE_OSPF_LSA, lsa); } /* Lock LSA. */ struct ospf_lsa * ospf_lsa_lock (struct ospf_lsa *lsa) { lsa->lock++; return lsa; } /* Unlock LSA. */ void ospf_lsa_unlock (struct ospf_lsa **lsa) { /* This is sanity check. */ if (!lsa || !*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), 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) { 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) { return link_info_set (s, DR (oi), oi->address->u.prefix4, LSA_LINK_TYPE_TRANSIT, 0, cost); } /* Describe type 3 link. */ else { 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, oi->output_cost); } /* 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), 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), 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), 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), 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 -- This value should be introduced from configuration. */ stream_putl (s, 0); } /* 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), 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); } 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, unsigned int 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", 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); 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); 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); #endif /* #if 0 */ if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("ospf_summary_lsa_install(): SPF scheduled"); } if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new); return new; } /* Install ASBR-summary-LSA to an area. */ 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); #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); } } /* 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; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (ospf, old); break; #endif /* HAVE_OPAQUE_LSA */ 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsdb = ospf->lsdb; break; default: lsdb = lsa->area->lsdb; break; } assert (lsdb); /* RFC 2328 13.2. Installing LSAs in the database Installing a new LSA in the database, either as the result of flooding or a newly self-originated LSA, may cause the OSPF routing table structure to be recalculated. The contents of the new LSA should be compared to the old instance, if present. If there is no difference, there is no need to recalculate the routing table. When comparing an LSA to its previous instance, the following are all considered to be differences in contents: o The LSA's Options field has changed. o One of the LSA instances has LS age set to MaxAge, and the other does not. o The length field in the LSA header has changed. o The body of the LSA (i.e., anything outside the 20-byte LSA header) has changed. Note that this excludes changes in LS Sequence Number and LS Checksum. */ /* Look up old LSA and determine if any SPF calculation or incremental update is needed */ old = ospf_lsdb_lookup (lsdb, lsa); /* Do comparision and record if recalc needed. */ rt_recalc = 0; if ( old == NULL || ospf_lsa_different(old, lsa)) rt_recalc = 1; /* 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", 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; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: if (IS_LSA_SELF (lsa)) lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ else { /* Incoming "oi" for this LSA has set at LSUpd reception. */ } /* Fallthrough */ case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_install (lsa, rt_recalc); break; #endif /* HAVE_OPAQUE_LSA */ 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_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), lsa); ospf_lsa_maxage (ospf, lsa); } return new; } static 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; } 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); /* 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", 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_ls lsa_prefix; ls_prefix_set (&lsa_prefix, 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); /* route_node_lookup */ } 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_ls 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), lsa); return; } ls_prefix_set (&lsa_prefix, lsa); if ((rn = route_node_get (ospf->maxage_lsa, (struct prefix *)&lsa_prefix)) != NULL) { if (rn->info != NULL) { 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) { #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* * As a general rule, whenever network topology has changed * (due to an LSA removal in this case), routing recalculation * should be triggered. However, this is not true for opaque * LSAs. Even if an opaque LSA instance is going to be removed * from the routing domain, it does not mean a change in network * topology, and thus, routing recalculation is not needed here. */ break; #endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: ospf_ase_incremental_update (ospf, lsa); break; default: ospf_spf_calculate_schedule (ospf); 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); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ 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); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ } OSPF_TIMER_ON (ospf->t_maxage_walker, ospf_lsa_maxage_walker, OSPF_LSA_MAXAGE_CHECK_INTERVAL); return 0; } struct ospf_lsa * ospf_lsa_lookup_by_prefix (struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p, struct in_addr router_id) { struct ospf_lsa *lsa; struct in_addr mask, id; struct lsa_header_mask { struct lsa_header header; struct in_addr mask; } *hmask; lsa = ospf_lsdb_lookup_by_id (lsdb, type, p->prefix, router_id); if (lsa == NULL) return NULL; masklen2ip (p->prefixlen, &mask); hmask = (struct lsa_header_mask *) lsa->data; if (mask.s_addr != hmask->mask.s_addr) { id.s_addr = p->prefix.s_addr | (~mask.s_addr); lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, router_id); if (!lsa) return NULL; } return lsa; } struct ospf_lsa * ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, struct in_addr id, struct in_addr adv_router) { 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: #endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* Currently not used. */ break; #endif /* HAVE_OPAQUE_LSA */ default: break; } return NULL; } struct ospf_lsa * ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) { struct ospf_lsa *match; #ifdef HAVE_OPAQUE_LSA /* * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) * is redefined to have two subfields; opaque-type and opaque-id. * However, it is harmless to treat the two sub fields together, as if * they two were forming a unique LSA-ID. */ #endif /* HAVE_OPAQUE_LSA */ match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router); if (match == NULL) if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) zlog_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) { #ifdef HAVE_OPAQUE_LSA /* 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; #endif /* HAVE_OPAQUE_LSA */ 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); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ } if (need_to_flush_ase) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ } /* * Make sure that the MaxAge LSA remover is executed immediately, * without conflicting to other threads. */ if (ospf->t_maxage != NULL) { OSPF_TIMER_OFF (ospf->t_maxage); thread_execute (master, ospf_maxage_lsa_remover, ospf, 0); } return; } #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; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_refresh (lsa); break; #endif /* HAVE_OPAQUE_LSA */ 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), 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), 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-0.99.22.4/ospfd/ospf_lsa.h0000644000175000017500000002720612211704467013332 00000000000000/* * 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 */ #if defined (HAVE_OPAQUE_LSA) #define OSPF_MAX_LSA 12 #else #define OSPF_MAX_LSA 8 #endif /* OSPF LSA Type definition. */ #define OSPF_UNKNOWN_LSA 0 #define OSPF_ROUTER_LSA 1 #define OSPF_NETWORK_LSA 2 #define OSPF_SUMMARY_LSA 3 #define OSPF_ASBR_SUMMARY_LSA 4 #define OSPF_AS_EXTERNAL_LSA 5 #define OSPF_GROUP_MEMBER_LSA 6 /* Not supported. */ #define OSPF_AS_NSSA_LSA 7 #define OSPF_EXTERNAL_ATTRIBUTES_LSA 8 /* Not supported. */ #define OSPF_OPAQUE_LINK_LSA 9 #define OSPF_OPAQUE_AREA_LSA 10 #define OSPF_OPAQUE_AS_LSA 11 #define OSPF_LSA_HEADER_SIZE 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]; }; #ifdef HAVE_OPAQUE_LSA #include "ospfd/ospf_opaque.h" #endif /* HAVE_OPAQUE_LSA */ /* Macros. */ #define GET_METRIC(x) get_metric(x) #define IS_EXTERNAL_METRIC(x) ((x) & 0x80) #define GET_AGE(x) (ntohs ((x)->data->ls_age) + time (NULL) - (x)->tv_recv) #define LS_AGE(x) (OSPF_LSA_MAXAGE < get_age(x) ? \ OSPF_LSA_MAXAGE : get_age(x)) #define IS_LSA_SELF(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_SELF)) #define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE) #define OSPF_LSA_UPDATE_DELAY 2 #define OSPF_LSA_UPDATE_TIMER_ON(T,F) \ if (!(T)) \ (T) = thread_add_timer (master, (F), 0, 2) /* 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 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 *); /* 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 *, unsigned int /* , 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-0.99.22.4/ospfd/ospf_lsdb.c0000644000175000017500000001620412177450262013470 00000000000000/* * 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), lsa, 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-0.99.22.4/ospfd/ospf_lsdb.h0000644000175000017500000000717612177450262013505 00000000000000/* * 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-0.99.22.4/ospfd/ospf_main.c0000644000175000017500000001707012177450262013472 00000000000000/* * 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 "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; struct thread thread; 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 (); access_list_init (); prefix_list_init (); /* OSPFd inits. */ ospf_if_init (); ospf_zebra_init (); /* OSPF vty inits. */ ospf_vty_init (); ospf_vty_show_init (); ospf_route_map_init (); #ifdef HAVE_SNMP ospf_snmp_init (); #endif /* HAVE_SNMP */ #ifdef HAVE_OPAQUE_LSA ospf_opaque_init (); #endif /* HAVE_OPAQUE_LSA */ sort_node (); /* Get configuration file. */ vty_read_config (config_file, config_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); /* Fetch next active thread. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return (0); } quagga-0.99.22.4/ospfd/ospf_neighbor.c0000644000175000017500000002651412132522417014337 00000000000000/* * 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 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) 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); } /* Free ospf_neighbor structure. */ ospf_nbr_free (nbr); } /* Check myself is in the neighbor list. */ int ospf_nbr_bidirectional (struct in_addr *router_id, struct in_addr *neighbors, int size) { int i; int max; max = size / sizeof (struct in_addr); for (i = 0; i < max; i ++) if (IPV4_ADDR_SAME (router_id, &neighbors[i])) return 1; return 0; } /* Add self to nbr list. */ void ospf_nbr_add_self (struct ospf_interface *oi) { struct 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; } #ifdef HAVE_OPAQUE_LSA int ospf_nbr_count_opaque_capable (struct ospf_interface *oi) { struct ospf_neighbor *nbr; struct route_node *rn; int count = 0; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) if (nbr->state == NSM_Full) if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) count++; return count; } #endif /* HAVE_OPAQUE_LSA */ /* lookup nbr by address - use this only if you know you must * otherwise use the ospf_nbr_lookup() wrapper, which deals * with virtual link 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) 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) key.u.prefix4 = ospfh->router_id; /* index vlink 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-0.99.22.4/ospfd/ospf_neighbor.h0000644000175000017500000000774512000052240014333 00000000000000/* * 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_add_self (struct ospf_interface *); extern int ospf_nbr_count (struct ospf_interface *, int); #ifdef HAVE_OPAQUE_LSA extern int ospf_nbr_count_opaque_capable (struct ospf_interface *); #endif /* HAVE_OPAQUE_LSA */ 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-0.99.22.4/ospfd/ospf_network.c0000644000175000017500000002056312177450262014240 00000000000000/* * 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, unsigned int 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, unsigned int 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, unsigned int 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, unsigned int 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, unsigned int ifindex) { u_char val; int ret, len; val = 0; len = sizeof (val); /* Prevent receiving self-origined multicast packets. */ ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); if (ret < 0) zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0) 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-0.99.22.4/ospfd/ospf_network.h0000644000175000017500000000274512177450262014247 00000000000000/* * 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 *, unsigned int); extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); extern int ospf_sock_init (void); extern void ospf_adjust_sndbuflen (struct ospf *, unsigned int); #endif /* _ZEBRA_OSPF_NETWORK_H */ quagga-0.99.22.4/ospfd/ospf_nsm.c0000644000175000017500000007120312177450262013341 00000000000000/* * 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) { #ifdef HAVE_OPAQUE_LSA switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */ if (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; } #endif /* HAVE_OPAQUE_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)) 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); #ifdef HAVE_OPAQUE_LSA /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); } #endif /* HAVE_OPAQUE_LSA */ if (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); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT)) LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); #endif /* HAVE_OPAQUE_LSA */ return 0; } static int nsm_exchange_done (struct ospf_neighbor *nbr) { if (ospf_ls_request_isempty (nbr)) return NSM_Full; /* Send Link State Request. */ 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); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) UNSET_FLAG (nbr->options, OSPF_OPTION_O); #endif /* HAVE_OPAQUE_LSA */ } 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]; } #ifdef HAVE_SNMP /* 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) ospfTrapVirtNbrStateChange(nbr); /* ospfNbrStateChange trap */ else /* To/From FULL, only managed by DR */ if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) || (nbr->oi->state == ISM_DR)) ospfTrapNbrStateChange(nbr); } #endif } 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); /* 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); } } #ifdef HAVE_OPAQUE_LSA ospf_opaque_nsm_change (nbr, old_state); #endif /* HAVE_OPAQUE_LSA */ /* 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; /* Generete NeighborChange ISM event. */ 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; } /* 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); nsm_change_state (nbr, next_state); } /* 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-0.99.22.4/ospfd/ospf_nsm.h0000644000175000017500000000656512177450262013357 00000000000000/* * 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-0.99.22.4/ospfd/ospf_opaque.c0000644000175000017500000021456512177450262014050 00000000000000/* * This is an implementation of rfc2370. * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /***** MTYPE definitions are not reflected to "memory.h" yet. *****/ #define MTYPE_OSPF_OPAQUE_FUNCTAB 0 #define MTYPE_OPAQUE_INFO_PER_TYPE 0 #define MTYPE_OPAQUE_INFO_PER_ID 0 #include #ifdef HAVE_OPAQUE_LSA #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ #ifdef HAVE_OSPF_TE #include "ospfd/ospf_te.h" #endif /* HAVE_OSPF_TE */ #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 (); #ifdef HAVE_OSPF_TE if (ospf_mpls_te_init () != 0) exit (1); #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) exit (1); #endif /* SUPPORT_OSPF_API */ return; } void ospf_opaque_term (void) { #ifdef HAVE_OSPF_TE ospf_mpls_te_term (); #endif /* HAVE_OSPF_TE */ #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; 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 (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_originate_schedule: Under blockade."); goto out; /* This is not an error, too. */ } if (delay0 != NULL) delay = *delay0; /* * There might be some entries that have been waiting for triggering * of per opaque-type re-origination get resumed. */ ospf_opaque_lsa_reoriginate_resume ( oi->opaque_lsa_self, (void *) oi); ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area); ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *) top); /* * Now, schedule origination of all Opaque-LSAs per opaque-type. */ if (! list_isempty (ospf_opaque_type9_funclist) && list_isempty (oi->opaque_lsa_self) && oi->t_opaque_lsa_self == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay); oi->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay); delay += OSPF_MIN_LS_INTERVAL; } if (! list_isempty (ospf_opaque_type10_funclist) && list_isempty (area->opaque_lsa_self) && area->t_opaque_lsa_self == NULL) { /* * One AREA may contain multiple OIs, but above 2nd and 3rd * conditions prevent from scheduling the originate function * again and again. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay); area->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type10_lsa_originate, area, delay); delay += OSPF_MIN_LS_INTERVAL; } if (! list_isempty (ospf_opaque_type11_funclist) && list_isempty (top->opaque_lsa_self) && top->t_opaque_lsa_self == NULL) { /* * One OSPF may contain multiple AREAs, but above 2nd and 3rd * conditions prevent from scheduling the originate function * again and again. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay); top->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type11_lsa_originate, top, delay); delay += OSPF_MIN_LS_INTERVAL; } /* * Following section treats a special situation that this node's * opaque capability has changed as "ON -> OFF -> ON". */ if (! list_isempty (ospf_opaque_type9_funclist) && ! list_isempty (oi->opaque_lsa_self)) { for (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 (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. */ } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Under blockade."); goto out; /* This is not an error, too. */ } /* Generate a dummy lsa to be passed for a lookup function. */ lsa = pseudo_lsa (oi, area, lsa_type, opaque_type); if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL) { struct ospf_opaque_functab *functab; if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " No associated function?: lsa_type(%u)," " opaque_type(%u)", lsa_type, opaque_type); goto out; } if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Cannot get a control info?: lsa_type(%u)," " opaque_type(%u)", lsa_type, opaque_type); goto out; } } if (oipt->t_opaque_lsa_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_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 = OSPF_MIN_LS_INTERVAL; /* XXX */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d" " sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay); out: return; } static struct ospf_lsa * pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type) { static struct ospf_lsa lsa = { 0 }; static struct lsa_header lsah = { 0 }; u_int32_t tmp; lsa.oi = oi; lsa.area = area; lsa.data = &lsah; lsah.type = lsa_type; tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */ lsah.id.s_addr = htonl (tmp); return &lsa; } static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; struct ospf_interface *oi; int rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?"); goto out; } oi = (struct ospf_interface *) oipt->owner; if ((top = oi_to_top (oi)) == NULL) { zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?"); goto out; } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE) || ! ospf_if_is_enable (oi) || ospf_nbr_count_opaque_capable (oi) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_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; 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: ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); break; default: zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); goto out; } delay = ospf_lsa_refresh_delay (lsa); if (IS_DEBUG_OSPF_EVENT) zlog_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); 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; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) { zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?"); goto out; } /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ if ((lsa = oipi->lsa) == NULL) { zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?"); goto out; } /* Delete this lsa from neighbor retransmit-list. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); break; default: zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); goto out; } /* Dequeue listnode entry from the list. */ listnode_delete (oipt->id_list, oipi); /* Avoid misjudgement in the next lookup. */ if (listcount (oipt->id_list) == 0) oipt->id_list->head = oipt->id_list->tail = NULL; /* Disassociate internal control information with the given lsa. */ 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 (lsa0->area->ospf, lsa); out: return; } /*------------------------------------------------------------------------* * Followings are control functions to block origination after restart. *------------------------------------------------------------------------*/ static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas) { struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; struct listnode *node1, *nnode1; struct listnode *node2, *nnode2; struct ospf_lsa *lsa; if ((top = oi_to_top (nbr->oi)) == NULL) goto out; /* * If an instance of self-originated Opaque-LSA is found in the given * LSA list, and it is not installed to LSDB yet, exclude it from the * list "nbr->ls_req". In this way, it is assured that an LSReq message, * which might be sent in the process of flooding, will not request for * the LSA to be flushed immediately; otherwise, depending on timing, * an LSUpd message will carry instances of target LSAs with MaxAge, * while other LSUpd message might carry old LSA instances (non-MaxAge). * Obviously, the latter would trigger miserable situations that repeat * installation and removal of unwanted LSAs indefinitely. */ for (ALL_LIST_ELEMENTS (lsas, node1, nnode1, lsa)) { /* Filter out unwanted LSAs. */ if (! IS_OPAQUE_LSA (lsa->data->type)) continue; if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id)) continue; /* * Don't touch an LSA which has MaxAge; two possible cases. * * 1) This LSA has originally flushed by myself (received LSUpd * message's router-id is equal to my router-id), and flooded * back by an opaque-capable router. * * 2) This LSA has expired in an opaque-capable router and thus * flushed by the router. */ if (IS_LSA_MAXAGE (lsa)) continue; /* If the LSA has installed in the LSDB, nothing to do here. */ if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL) continue; /* Ok, here we go. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: oi = nbr->oi; ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; case OSPF_OPAQUE_AREA_LSA: area = nbr->oi->area; for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; case OSPF_OPAQUE_AS_LSA: for (ALL_LIST_ELEMENTS (top->oiflist, node2, nnode2, oi)) ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; default: break; } } out: return; } static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { struct route_node *rn; struct ospf_neighbor *onbr; struct ospf_lsa *ls_req; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((onbr = rn->info) == NULL) continue; if (onbr == inbr) continue; if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL) continue; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa)); ospf_ls_request_delete (onbr, ls_req); /* ospf_check_nbr_loading (onbr);*//* XXX */ } return; } void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; u_char before; if ((top = oi_to_top (nbr->oi)) == NULL) return; before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque); /* * Since these LSA entries are not yet installed into corresponding * LSDB, just flush them without calling ospf_ls_maxage() afterward. */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AREA_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AS_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); ospf_flood_through_as (top, NULL/*inbr*/, lsa); break; default: zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type); return; } ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Block Opaque-LSA origination: OFF -> ON"); } } void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; int delay; struct ospf_interface *oi; struct listnode *node, *nnode; if ((top = oi_to_top (nbr->oi)) == NULL) return; if (!IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) return; switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); /* Callback function... */ break; case OSPF_OPAQUE_AREA_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); /* Callback function... */ break; case OSPF_OPAQUE_AS_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) ospf_opaque_type11_lsa_rxmt_nbr_check (top); /* Callback function... */ break; default: zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type); return; } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Block Opaque-LSA origination: ON -> OFF"); return; /* Blocking still in progress. */ } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) return; /* Opaque capability condition must have changed. */ /* Ok, let's start origination of Opaque-LSAs. */ delay = OSPF_MIN_LS_INTERVAL; for (ALL_LIST_ELEMENTS (top->oiflist, node, nnode, oi)) { if (! ospf_if_is_enable (oi) || ospf_nbr_count_opaque_capable (oi) == 0) continue; ospf_opaque_lsa_originate_schedule (oi, &delay); } return; } static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) { unsigned long n; n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA); if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi)); UNSET_FLAG (oi->area->ospf->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); } return; } static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area) { struct listnode *node; struct ospf_interface *oi; unsigned long n = 0; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { if (area->area_id.s_addr != OSPF_AREA_BACKBONE && oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA); if (n > 0) break; } if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id)); UNSET_FLAG (area->ospf->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); } return; } static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top) { struct listnode *node; struct ospf_interface *oi; unsigned long n = 0; for (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi)) { switch (oi->type) { case OSPF_IFTYPE_VIRTUALLINK: continue; default: break; } n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA); if (n > 0) goto out; } if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-11 Opaque-LSAs: Flush completed"); UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); } out: return; } static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) { struct route_node *rn; struct ospf_neighbor *nbr; struct ospf *top; unsigned long n = 0; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((nbr = rn->info) == NULL) continue; if ((top = oi_to_top (nbr->oi)) == NULL) continue; if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id)) continue; n += ospf_ls_retransmit_count_self (nbr, lsa_type); } return n; } /*------------------------------------------------------------------------* * Followings are util functions; probably be used by Opaque-LSAs only... *------------------------------------------------------------------------*/ void htonf (float *src, float *dst) { u_int32_t lu1, lu2; memcpy (&lu1, src, sizeof (u_int32_t)); lu2 = htonl (lu1); memcpy (dst, &lu2, sizeof (u_int32_t)); return; } void ntohf (float *src, float *dst) { u_int32_t lu1, lu2; memcpy (&lu1, src, sizeof (u_int32_t)); lu2 = ntohl (lu1); memcpy (dst, &lu2, sizeof (u_int32_t)); return; } struct ospf * oi_to_top (struct ospf_interface *oi) { struct ospf *top = NULL; struct ospf_area *area; if (oi == NULL || (area = oi->area) == NULL || (top = area->ospf) == NULL) zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?"); return top; } #endif /* HAVE_OPAQUE_LSA */ quagga-0.99.22.4/ospfd/ospf_opaque.h0000644000175000017500000001421312132522417014032 00000000000000/* * 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) /* * Usage of Opaque-LSA administrative flags in "struct ospf". * * 7 6 5 4 3 2 1 0 * +---+---+---+---+---+---+---+---+ * |///|///|///|///|B11|B10|B09| O | * +---+---+---+---+---+---+---+---+ * |<--------->| A * | +--- Operation status (operational = 1) * +----------- Blocking status for each LSA type */ #define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \ CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \ OPAQUE_BLOCK_TYPE_10_LSA_BIT | \ OPAQUE_BLOCK_TYPE_11_LSA_BIT)) /* * Opaque LSA's link state ID is redefined as follows. * * 24 16 8 0 * +--------+--------+--------+--------+ * |tttttttt|........|........|........| * +--------+--------+--------+--------+ * |<-Type->|<------- Opaque ID ------>| */ #define LSID_OPAQUE_TYPE_MASK 0xff000000 /* 8 bits */ #define LSID_OPAQUE_ID_MASK 0x00ffffff /* 24 bits */ #define GET_OPAQUE_TYPE(lsid) \ (((u_int32_t)(lsid) & LSID_OPAQUE_TYPE_MASK) >> 24) #define GET_OPAQUE_ID(lsid) \ ((u_int32_t)(lsid) & LSID_OPAQUE_ID_MASK) #define SET_OPAQUE_LSID(type, id) \ ((((type) << 24) & LSID_OPAQUE_TYPE_MASK) \ | ((id) & LSID_OPAQUE_ID_MASK)) /* * Opaque LSA types will be assigned by IANA. * */ #define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 #define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 #define OPAQUE_TYPE_GRACE_LSA 3 /* Followings types are proposed in internet-draft documents. */ #define OPAQUE_TYPE_8021_QOSPF 129 #define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY 224 #define OPAQUE_TYPE_FLOODGATE 225 /* Ugly hack to make use of an unallocated value for wildcard matching! */ #define OPAQUE_TYPE_WILDCARD 0 #define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ ( 4 <= (type) && (type) <= 127) #define OPAQUE_TYPE_RANGE_RESERVED(type) \ (127 < (type) && (type) <= 255) #define VALID_OPAQUE_INFO_LEN(lsahdr) \ ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \ ((ntohs((lsahdr)->length) % sizeof (u_int32_t)) == 0)) /* Prototypes. */ 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_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas); extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); extern void htonf (float *src, float *dst); extern void ntohf (float *src, float *dst); extern struct ospf *oi_to_top (struct ospf_interface *oi); #endif /* _ZEBRA_OSPF_OPAQUE_H */ quagga-0.99.22.4/ospfd/ospf_packet.c0000644000175000017500000034651412211704467014023 00000000000000/* * 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]; 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 *) ""; 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; #endif /* WANT_OSPF_WRITE_FRAGMENT */ u_int16_t maxdatasize; #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); #endif /* WANT_OSPF_WRITE_FRAGMENT */ /* 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); /* 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); 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_T)) { /* * This router does not support non-zero TOS. * Drop this Hello packet not to establish neighbor relationship. */ zlog_warn ("Packet %s [Hello:RECV]: T-bit on, drop it.", inet_ntoa (ospfh->router_id)); return; } #endif /* REJECT_IF_TBIT_ON */ #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) && CHECK_FLAG (hello->options, OSPF_OPTION_O)) { /* * This router does know the correct usage of O-bit * the bit should be set in DD packet only. */ zlog_warn ("Packet %s [Hello:RECV]: O-bit abuse?", inet_ntoa (ospfh->router_id)); #ifdef STRICT_OBIT_USAGE_CHECK return; /* Reject this packet. */ #else /* STRICT_OBIT_USAGE_CHECK */ UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ #endif /* STRICT_OBIT_USAGE_CHECK */ } #endif /* HAVE_OPAQUE_LSA */ /* new for NSSA is to ensure that NP is on and E is off */ 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; } #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsah->type) && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } #endif /* HAVE_OPAQUE_LSA */ switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ /* 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_T)) { /* * In Hello protocol, optional capability must have checked * to prevent this T-bit enabled router be my neighbor. */ zlog_warn ("Packet[DD]: Neighbor %s: T-bit on?", inet_ntoa (nbr->router_id)); return; } #endif /* REJECT_IF_TBIT_ON */ #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (dd->options, OSPF_OPTION_O) && !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { /* * This node is not configured to handle O-bit, for now. * Clear it to ignore unsupported capability proposed by neighbor. */ UNSET_FLAG (dd->options, OSPF_OPTION_O); } #endif /* HAVE_OPAQUE_LSA */ /* 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; #ifdef HAVE_OPAQUE_LSA 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. */ } } #endif /* HAVE_OPAQUE_LSA */ OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); /* continue processing rest of packet. */ ospf_db_desc_proc (s, oi, nbr, dd, size); break; case NSM_Exchange: if (ospf_db_desc_is_dup (dd, nbr)) { if (IS_SET_DD_MS (nbr->dd_flags)) /* Master: discard duplicated DD packet. */ zlog_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); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { #ifdef STRICT_OBIT_USAGE_CHECK if ((IS_OPAQUE_LSA(lsah->type) && ! CHECK_FLAG (lsah->options, OSPF_OPTION_O)) || (! IS_OPAQUE_LSA(lsah->type) && CHECK_FLAG (lsah->options, OSPF_OPTION_O))) { /* * This neighbor must know the exact usage of O-bit; * the bit will be set in Type-9,10,11 LSAs only. */ zlog_warn ("LSA[Type%d:%s]: O-bit abuse?", lsah->type, inet_ntoa (lsah->id)); continue; } #endif /* STRICT_OBIT_USAGE_CHECK */ /* Do not take in AS External Opaque-LSAs if we are a stub. */ if (lsah->type == OSPF_OPAQUE_AS_LSA && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) { if (IS_DEBUG_OSPF_EVENT) zlog_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; } #endif /* HAVE_OPAQUE_LSA */ /* Create OSPF LSA instance. */ lsa = ospf_lsa_new (); /* We may wish to put some error checking if type NSSA comes in and area not in NSSA mode */ switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa->area = NULL; break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ /* Fallthrough */ #endif /* HAVE_OPAQUE_LSA */ default: lsa->area = oi->area; break; } lsa->data = ospf_lsa_data_new (length); memcpy (lsa->data, lsah, length); if (IS_DEBUG_OSPF_EVENT) zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update", lsa->data->type, inet_ntoa (lsa->data->id), lsa); listnode_add (lsas, lsa); } return lsas; } /* Cleanup Update list. */ 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 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); #ifdef HAVE_OPAQUE_LSA /* * If self-originated Opaque-LSAs that have flooded before restart * are contained in the received LSUpd message, corresponding LSReq * messages to be sent may have to be modified. * To eliminate possible race conditions such that flushing and normal * updating for the same LSA would take place alternately, this trick * must be done before entering to the loop below. */ /* XXX: Why is this Opaque specific? Either our core code is deficient * and this should be fixed generally, or Opaque is inventing strawman * problems */ ospf_opaque_adjust_lsreq (nbr, lsas); #endif /* HAVE_OPAQUE_LSA */ #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, 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_nbr_count (oi, NSM_Exchange) + ospf_nbr_count (oi, NSM_Loading)) == 0) { /* (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); } #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) { /* * Even if initial flushing seems to be completed, there might * be a case that self-originated LSA with MaxAge still remain * in the routing domain. * Just send an LSAck message to cease retransmission. */ if (IS_LSA_MAXAGE (lsa)) { zlog_warn ("LSA[%s]: Boomerang effect?", dump_lsa_key (lsa)); ospf_ls_ack_send (nbr, lsa); ospf_lsa_discard (lsa); if (current != NULL && ! IS_LSA_MAXAGE (current)) ospf_opaque_lsa_refresh_schedule (current); continue; } /* * If an instance of self-originated Opaque-LSA is not found * in the LSDB, there are some possible cases here. * * 1) This node lost opaque-capability after restart. * 2) Else, a part of opaque-type is no more supported. * 3) Else, a part of opaque-id is no more supported. * * Anyway, it is still this node's responsibility to flush it. * Otherwise, the LSA instance remains in the routing domain * until its age reaches to MaxAge. */ /* 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; } } #endif /* HAVE_OPAQUE_LSA */ /* 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", 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), int2tv (OSPF_MIN_LS_ARRIVAL)) >= 0) /* Trap NSSA type later.*/ ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); DISCARD_LSA (lsa, 8); } } } #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 && lsr->data->ls_seqnum == lsa->data->ls_seqnum) { #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsr->data->type)) ospf_opaque_ls_ack_received (nbr, lsr); #endif /* HAVE_OPAQUE_LSA */ 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; unsigned int 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 */ #ifdef HAVE_OPAQUE_LSA 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. */ #endif 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 (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 (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); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_SET_DD_I (nbr->dd_flags) || CHECK_FLAG (nbr->options, OSPF_OPTION_O)) /* * Set O-bit in the outgoing DD packet for capablity negotiation, * if one of following case is applicable. * * 1) WaitTimer expiration event triggered the neighbor state to * change to Exstart, but no (valid) DD packet has received * from the neighbor yet. * * 2) At least one DD packet with O-bit on has received from the * neighbor. */ SET_FLAG (options, OSPF_OPTION_O); } #endif /* HAVE_OPAQUE_LSA */ stream_putc (s, options); /* 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) { #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && (! CHECK_FLAG (options, OSPF_OPTION_O))) { /* Suppress advertising opaque-informations. */ /* Remove LSA from DB summary list. */ ospf_lsdb_delete (lsdb, lsa); continue; } #endif /* HAVE_OPAQUE_LSA */ if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) { struct lsa_header *lsah; u_int16_t ls_age; /* DD packet overflows interface MTU. */ if (length + OSPF_LSA_HEADER_SIZE > ospf_packet_max (oi)) break; /* Keep pointer to LS age. */ lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_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"); 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, dst %s", listcount (update), 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 (); 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; /* Set destination IP address. */ op->dst = dst; /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); } static int ospf_ls_ack_send_event (struct thread *thread) { struct ospf_interface *oi = THREAD_ARG (thread); oi->t_ls_ack_direct = NULL; while (listcount (oi->ls_ack_direct.ls_ack)) ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack, oi->ls_ack_direct.dst); return 0; } void ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf_interface *oi = nbr->oi; if (listcount (oi->ls_ack_direct.ls_ack) == 0) oi->ls_ack_direct.dst = nbr->address.u.prefix4; listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa)); if (oi->t_ls_ack_direct == NULL) oi->t_ls_ack_direct = thread_add_event (master, ospf_ls_ack_send_event, oi, 0); } /* Send Link State Acknowledgment delayed. */ void ospf_ls_ack_send_delayed (struct ospf_interface *oi) { struct in_addr dst; /* Decide destination address. */ /* RFC2328 Section 13.5 On non-broadcast networks, delayed Link State Acknowledgment packets must be unicast separately over each adjacency (i.e., neighbor whose state is >= Exchange). */ if (oi->type == OSPF_IFTYPE_NBMA) { struct ospf_neighbor *nbr; struct route_node *rn; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) while (listcount (oi->ls_ack)) ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4); return; } if (oi->type == OSPF_IFTYPE_VIRTUALLINK) dst.s_addr = oi->vl_data->peer_addr.s_addr; else if (oi->state == ISM_DR || oi->state == ISM_Backup) dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else if (oi->type == OSPF_IFTYPE_POINTOPOINT) dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else 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-0.99.22.4/ospfd/ospf_packet.h0000644000175000017500000001347612051607643014026 00000000000000/* * 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-0.99.22.4/ospfd/ospf_route.c0000644000175000017500000006574612177450262013721 00000000000000/* * 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-0.99.22.4/ospfd/ospf_route.h0000644000175000017500000001122712177450262013707 00000000000000/* * 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; unsigned int 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-0.99.22.4/ospfd/ospf_routemap.c0000644000175000017500000005305612177450262014406 00000000000000/* * 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, "%% 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 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, "%% 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 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, "%% 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; } /* 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, "%% 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; } /* `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 }; /* `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; 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, }; DEFUN (match_ip_nexthop, match_ip_nexthop_cmd, "match ip next-hop (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") { return ospf_route_match_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (no_match_ip_nexthop, no_match_ip_nexthop_cmd, "no match ip next-hop", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip next-hop", NULL); return ospf_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_match_ip_nexthop, no_match_ip_nexthop_val_cmd, "no match ip next-hop (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") DEFUN (match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD", MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return ospf_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); } DEFUN (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); } ALIAS (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_val_cmd, "no match ip next-hop prefix-list WORD", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_address, match_ip_address_cmd, "match ip address (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") { return ospf_route_match_add (vty, vty->index, "ip address", argv[0]); } DEFUN (no_match_ip_address, no_match_ip_address_cmd, "no match ip address", NO_STR MATCH_STR IP_STR "Match address of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip address", NULL); return ospf_route_match_delete (vty, vty->index, "ip address", argv[0]); } ALIAS (no_match_ip_address, no_match_ip_address_val_cmd, "no match ip address (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") DEFUN (match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD", MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return ospf_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); } DEFUN (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); } ALIAS (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, "no match ip address prefix-list WORD", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_interface, match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return ospf_route_match_add (vty, vty->index, "interface", argv[0]); } DEFUN (no_match_interface, no_match_interface_cmd, "no match interface", NO_STR MATCH_STR "Match first hop interface of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "interface", NULL); return ospf_route_match_delete (vty, vty->index, "interface", argv[0]); } ALIAS (no_match_interface, no_match_interface_val_cmd, "no match interface WORD", NO_STR MATCH_STR "Match first hop interface of route\n" "Interface name\n") DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", SET_STR "Metric value for destination routing protocol\n" "Metric value\n") { return ospf_route_set_add (vty, vty->index, "metric", argv[0]); } DEFUN (no_set_metric, no_set_metric_cmd, "no set metric", NO_STR SET_STR "Metric value for destination routing protocol\n") { if (argc == 0) return ospf_route_set_delete (vty, vty->index, "metric", NULL); return ospf_route_set_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_set_metric, no_set_metric_val_cmd, "no set metric <0-4294967295>", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\n") DEFUN (set_metric_type, set_metric_type_cmd, "set metric-type (type-1|type-2)", SET_STR "Type of metric for destination routing protocol\n" "OSPF[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") /* Route-map init */ void ospf_route_map_init (void) { route_map_init (); route_map_init_vty (); route_map_add_hook (ospf_route_map_update); route_map_delete_hook (ospf_route_map_update); route_map_event_hook (ospf_route_map_event); route_map_install_match (&route_match_ip_nexthop_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); route_map_install_match (&route_match_interface_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_metric_type_cmd); install_element (RMAP_NODE, &match_ip_nexthop_cmd); install_element (RMAP_NODE, &no_match_ip_nexthop_cmd); install_element (RMAP_NODE, &no_match_ip_nexthop_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); install_element (RMAP_NODE, &match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_val_cmd); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); install_element (RMAP_NODE, &match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_metric_type_cmd); install_element (RMAP_NODE, &no_set_metric_type_cmd); install_element (RMAP_NODE, &no_set_metric_type_val_cmd); } quagga-0.99.22.4/ospfd/ospf_snmp.c0000644000175000017500000021637412177450262013533 00000000000000/* 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 = {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 > 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 > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, ls_id); } /* Router ID. */ offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; len = offsetlen; if (len <= 0) router_id_next = 1; else { router_id_next = 0; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, router_id); } lsa = lsdb_lookup_next (area, type, type_next, ls_id, ls_id_next, router_id, router_id_next); if (lsa) { /* Fill in length. */ *length = v->namelen + OSPF_LSDB_ENTRY_OFFSET; /* Fill in value. */ offset = name + v->namelen; oid_copy_addr (offset, area_id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; *offset = lsa->data->type; offset++; oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); return lsa; } } while ((area = ospf_area_lookup_next (ospf, area_id, 0)) != NULL); } return NULL; } static u_char * ospfLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_lsa *lsa; struct lsa_header *lsah; struct in_addr area_id; u_char type; struct in_addr ls_id; struct in_addr router_id; struct ospf *ospf; 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; unsigned int len; struct ospf *ospf; struct ospf_area *area; struct ospf_area_range *range; struct prefix_ipv4 p; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; ospf = ospf_lookup (); if (exact) { /* Area ID + Range Network. */ if (v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE != *length) return NULL; /* Set OID offset for Area ID. */ offset = name + v->namelen; /* Lookup area first. */ oid2in_addr (offset, IN_ADDR_SIZE, area_id); area = ospf_area_lookup_by_area_id (ospf, *area_id); if (! area) return NULL; offset += IN_ADDR_SIZE; /* Lookup area range. */ oid2in_addr (offset, IN_ADDR_SIZE, range_net); p.prefix = *range_net; return ospf_area_range_lookup (area, &p); } else { /* Set OID offset for Area ID. */ offset = name + v->namelen; offsetlen = *length - v->namelen; len = offsetlen; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, area_id); /* First we search area. */ if (len == IN_ADDR_SIZE) area = ospf_area_lookup_by_area_id (ospf,*area_id); else area = ospf_area_lookup_next (ospf, area_id, len == 0 ? 1 : 0); if (area == NULL) return NULL; do { offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; len = offsetlen; if (len < 0) len = 0; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, range_net); range = ospf_area_range_lookup_next (area, range_net, len == 0 ? 1 : 0); if (range) { /* Fill in length. */ *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; /* Fill in value. */ offset = name + v->namelen; oid_copy_addr (offset, area_id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; oid_copy_addr (offset, range_net, IN_ADDR_SIZE); return range; } } while ((area = ospf_area_lookup_next (ospf, area_id, 0)) != NULL); } return NULL; } static u_char * ospfAreaRangeEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_area_range *range; struct in_addr area_id; struct in_addr range_net; struct in_addr mask; struct ospf *ospf; 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; unsigned int ifindex; struct interface *ifp; }; static struct ospf_snmp_if * ospf_snmp_if_new (void) { return XCALLOC (0, sizeof (struct ospf_snmp_if)); } static void ospf_snmp_if_free (struct ospf_snmp_if *osif) { XFREE (0, 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; unsigned int 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, unsigned int *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, unsigned int *ifindex, int ifaddr_next, int 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, unsigned int *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; int 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) { unsigned int 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, unsigned int *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; int 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. */ unsigned int 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); 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, unsigned int *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, unsigned int *ifindex, int first) { struct listnode *nn; struct ospf_interface *oi; struct ospf_neighbor *nbr; struct route_node *rn; struct ospf_neighbor *min = NULL; struct ospf *ospf = ospf; ospf = ospf_lookup (); 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, unsigned int *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; unsigned int 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-0.99.22.4/ospfd/ospf_snmp.h0000644000175000017500000000264312000052240013503 00000000000000/* 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-0.99.22.4/ospfd/ospf_spf.c0000644000175000017500000012355712177450262013346 00000000000000/* 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" 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; /* 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", 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); /* Free SPF vertices, but not the list. List has ospf_vertex_free * as deconstructor. */ list_delete_all_node (&vertex_list); /* Increment SPF Calculation Counter. */ area->spf_calculation++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); } /* 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; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: Timer (SPF calculation expire)"); ospf->t_spf_calc = NULL; /* Allocate new table tree. */ new_table = route_table_init (); new_rtrs = route_table_init (); ospf_vl_unapprove (ospf); /* Calculate SPF for each area. */ for (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); } /* SPF for backbone, if required */ if (ospf->backbone) ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); ospf_vl_shut_unapproved (ospf); ospf_ia_routing (ospf, new_table, new_rtrs); ospf_prune_unreachable_networks (new_table); ospf_prune_unreachable_routers (new_rtrs); /* AS-external-LSA calculation should not be performed here. */ /* If new Router Route is installed, then schedule re-calculate External routes. */ if (1) ospf_ase_calculate_schedule (ospf); ospf_ase_calculate_timer_add (ospf); /* Update routing table. */ ospf_route_install (ospf, new_table); /* Update ABR/ASBR routing table */ if (ospf->old_rtrs) { /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */ /* ospf_route_delete (ospf->old_rtrs); */ ospf_rtrs_free (ospf->old_rtrs); } ospf->old_rtrs = ospf->new_rtrs; ospf->new_rtrs = new_rtrs; if (IS_OSPF_ABR (ospf)) ospf_abr_task (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation complete"); return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ void ospf_spf_calculate_schedule (struct ospf *ospf) { 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; /* 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", 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); ospf->t_spf_calc = thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); } quagga-0.99.22.4/ospfd/ospf_spf.h0000644000175000017500000000422612000052240013315 00000000000000/* * 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 */ }; extern void ospf_spf_calculate_schedule (struct ospf *); extern void ospf_rtrs_free (struct route_table *); /* void ospf_spf_calculate_timer_add (); */ #endif /* _QUAGGA_OSPF_SPF_H */ quagga-0.99.22.4/ospfd/ospf_te.c0000644000175000017500000014722612177450262013165 00000000000000/* * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /***** MTYPE definition is not reflected to "memory.h" yet. *****/ #define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 #include #ifdef HAVE_OSPF_TE #ifndef HAVE_OPAQUE_LSA #error "Wrong configure option" #endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" /* Following structure are internal use only. */ struct ospf_mpls_te { enum { disabled, enabled } status; /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ 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; #define LPFLG_LOOKUP_DONE 0x1 #define LPFLG_LSA_ENGAGED 0x2 #define LPFLG_LSA_FORCED_REFRESH 0x4 /* Store Link-TLV in network byte order. */ struct te_tlv_link link_header; struct te_link_subtlv_link_type link_type; struct te_link_subtlv_link_id link_id; struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; struct te_link_subtlv_te_metric te_metric; struct te_link_subtlv_max_bw max_bw; struct te_link_subtlv_max_rsv_bw max_rsv_bw; struct te_link_subtlv_unrsv_bw unrsv_bw; struct te_link_subtlv_rsc_clsclr rsc_clsclr; }; /* * Global variable to manage Opaque-LSA/MPLS-TE on this node. * Note that all parameter values are stored in network byte order. */ static struct ospf_mpls_te OspfMplsTE; enum oifstate { OI_ANY, OI_DOWN, OI_UP }; enum sched_opcode { REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA }; /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for MPLS-TE handling. *------------------------------------------------------------------------*/ static int ospf_mpls_te_new_if (struct interface *ifp); static int ospf_mpls_te_del_if (struct interface *ifp); static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router (struct vty *vty); static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); static int ospf_mpls_te_lsa_originate (void *arg); static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); static void del_mpls_te_link (void *val); static void ospf_mpls_te_register_vty (void); int ospf_mpls_te_init (void) { int rc; rc = ospf_register_opaque_functab ( OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, ospf_mpls_te_new_if, ospf_mpls_te_del_if, ospf_mpls_te_ism_change, ospf_mpls_te_nsm_change, ospf_mpls_te_config_write_router, ospf_mpls_te_config_write_if, NULL,/* ospf_mpls_te_config_write_debug */ ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate, ospf_mpls_te_lsa_refresh, NULL,/* ospf_mpls_te_new_lsa_hook */ NULL /* ospf_mpls_te_del_lsa_hook */); if (rc != 0) { zlog_warn ("ospf_mpls_te_init: Failed to register functions"); goto out; } memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); OspfMplsTE.status = disabled; OspfMplsTE.iflist = list_new (); OspfMplsTE.iflist->del = del_mpls_te_link; ospf_mpls_te_register_vty (); out: return rc; } void ospf_mpls_te_term (void) { list_delete (OspfMplsTE.iflist); OspfMplsTE.iflist = NULL; OspfMplsTE.status = disabled; ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); return; } /*------------------------------------------------------------------------* * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ static void del_mpls_te_link (void *val) { XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); return; } static u_int32_t get_mpls_te_instance_value (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, enum sched_opcode), enum sched_opcode 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)) { if ((area = lp->area) == NULL) continue; if (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)) lp->flags |= LPFLG_LOOKUP_DONE; } for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) if (lp->area != NULL) lp->flags &= ~LPFLG_LOOKUP_DONE; return; } static void set_mpls_te_router_addr (struct in_addr ipv4) { OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); OspfMplsTE.router_addr.value = ipv4; return; } static void set_linkparams_link_header (struct mpls_te_link *lp) { struct te_tlv_header *tlvh; u_int16_t length = 0; /* TE_LINK_SUBTLV_LINK_TYPE */ if (ntohs (lp->link_type.header.type) != 0) length += TLV_SIZE (&lp->link_type.header); /* TE_LINK_SUBTLV_LINK_ID */ if (ntohs (lp->link_id.header.type) != 0) length += TLV_SIZE (&lp->link_id.header); /* TE_LINK_SUBTLV_LCLIF_IPADDR */ if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL && ntohs (tlvh->type) != 0) length += TLV_SIZE (tlvh); /* TE_LINK_SUBTLV_RMTIF_IPADDR */ if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL && ntohs (tlvh->type) != 0) length += TLV_SIZE (tlvh); /* TE_LINK_SUBTLV_TE_METRIC */ if (ntohs (lp->te_metric.header.type) != 0) length += TLV_SIZE (&lp->te_metric.header); /* TE_LINK_SUBTLV_MAX_BW */ if (ntohs (lp->max_bw.header.type) != 0) length += TLV_SIZE (&lp->max_bw.header); /* TE_LINK_SUBTLV_MAX_RSV_BW */ if (ntohs (lp->max_rsv_bw.header.type) != 0) length += TLV_SIZE (&lp->max_rsv_bw.header); /* TE_LINK_SUBTLV_UNRSV_BW */ if (ntohs (lp->unrsv_bw.header.type) != 0) length += TLV_SIZE (&lp->unrsv_bw.header); /* TE_LINK_SUBTLV_RSC_CLSCLR */ if (ntohs (lp->rsc_clsclr.header.type) != 0) length += TLV_SIZE (&lp->rsc_clsclr.header); lp->link_header.header.type = htons (TE_TLV_LINK); lp->link_header.header.length = htons (length); return; } static void set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) { lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); switch (oi->type) { case OSPF_IFTYPE_POINTOPOINT: lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; break; case OSPF_IFTYPE_BROADCAST: case OSPF_IFTYPE_NBMA: lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; break; default: /* Not supported yet. *//* XXX */ lp->link_type.header.type = htons (0); break; } return; } static void set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) { struct ospf_neighbor *nbr; int done = 0; lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); lp->link_id.header.length = htons (sizeof (lp->link_id.value)); /* * The Link ID is identical to the contents of the Link ID field * in the Router LSA for these link types. */ switch (oi->type) { case OSPF_IFTYPE_POINTOPOINT: /* Take the router ID of the neighbor. */ if ((nbr = ospf_nbr_lookup_ptop (oi)) && nbr->state == NSM_Full) { lp->link_id.value = nbr->router_id; done = 1; } break; case OSPF_IFTYPE_BROADCAST: case OSPF_IFTYPE_NBMA: /* Take the interface address of the designated router. */ if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL) break; if (nbr->state == NSM_Full || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) && ospf_nbr_count (oi, NSM_Full) > 0)) { lp->link_id.value = DR (oi); done = 1; } break; default: /* Not supported yet. *//* XXX */ lp->link_id.header.type = htons (0); break; } if (! done) { struct in_addr mask; masklen2ip (oi->address->prefixlen, &mask); lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; } return; } static void set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) { lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); lp->te_metric.value = htonl (te_metric); return; } static void set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) { lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); htonf (fp, &lp->max_bw.value); return; } static void set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) { lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); htonf (fp, &lp->max_rsv_bw.value); return; } static void set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) { /* Note that TLV-length field is the size of array. */ lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); htonf (fp, &lp->unrsv_bw.value [priority]); return; } static void set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) { lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); lp->rsc_clsclr.value = htonl (classcolor); return; } static void initialize_linkparams (struct mpls_te_link *lp) { struct interface *ifp = lp->ifp; struct ospf_interface *oi; float fval; int i; if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) return; /* * Try to set initial values those can be derived from * zebra-interface information. */ set_linkparams_link_type (oi, lp); /* * Linux and *BSD kernel holds bandwidth parameter as an "int" type. * We may have to reconsider, if "ifp->bandwidth" type changes to float. */ fval = (float)((ifp->bandwidth ? ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); set_linkparams_max_bw (lp, &fval); set_linkparams_max_rsv_bw (lp, &fval); for (i = 0; i < 8; i++) set_linkparams_unrsv_bw (lp, i, &fval); return; } static int is_mandated_params_set (struct mpls_te_link *lp) { int rc = 0; if (ntohs (OspfMplsTE.router_addr.header.type) == 0) goto out; if (ntohs (lp->link_type.header.type) == 0) goto out; if (ntohs (lp->link_id.header.type) == 0) goto out; rc = 1; out: return rc; } /*------------------------------------------------------------------------* * Followings are callback functions against generic Opaque-LSAs handling. *------------------------------------------------------------------------*/ static int ospf_mpls_te_new_if (struct interface *ifp) { struct mpls_te_link *new; int rc = -1; if (lookup_linkparams_by_ifp (ifp) != NULL) { zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp); rc = 0; /* Do nothing here. */ goto out; } new = XCALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, sizeof (struct mpls_te_link)); if (new == NULL) { zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror (errno)); goto out; } new->area = NULL; new->flags = 0; new->instance = get_mpls_te_instance_value (); new->ifp = ifp; initialize_linkparams (new); listnode_add (OspfMplsTE.iflist, new); /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; out: return rc; } static int ospf_mpls_te_del_if (struct interface *ifp) { struct mpls_te_link *lp; int rc = -1; if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL) { 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_LINKPARAMS, lp); } /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; /*out:*/ return rc; } static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) { struct te_link_subtlv_link_type old_type; struct te_link_subtlv_link_id old_id; struct mpls_te_link *lp; if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL) { zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); goto out; } if (oi->area == NULL || oi->area->ospf == NULL) { zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", IF_NAME (oi)); goto out; } #ifdef notyet if ((lp->area != NULL && ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id)) || (lp->area != NULL && oi->area == NULL)) { /* How should we consider this case? */ zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } #endif /* Keep Area information in conbination with linkparams. */ lp->area = oi->area; switch (oi->state) { case ISM_PointToPoint: case ISM_DROther: case ISM_Backup: case ISM_DR: old_type = lp->link_type; old_id = lp->link_id; set_linkparams_link_type (oi, lp); set_linkparams_link_id (oi, lp); if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) || old_type.link_type.value != lp->link_type.link_type.value) || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } break; default: lp->link_type.header.type = htons (0); lp->link_id.header.type = htons (0); if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); break; } out: return; } static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) { /* So far, nothing to do here. */ return; } /*------------------------------------------------------------------------* * Followings are OSPF protocol processing functions for MPLS-TE. *------------------------------------------------------------------------*/ static void build_tlv_header (struct stream *s, struct te_tlv_header *tlvh) { stream_put (s, tlvh, sizeof (struct te_tlv_header)); return; } static void build_router_tlv (struct stream *s) { struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->link_type.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->link_id.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; if (tlvh != NULL && ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; if (tlvh != NULL && ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->te_metric.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->max_bw.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->unrsv_bw.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_tlv (struct stream *s, struct mpls_te_link *lp) { set_linkparams_link_header (lp); build_tlv_header (s, &lp->link_header.header); build_link_subtlv_link_type (s, lp); build_link_subtlv_link_id (s, lp); build_link_subtlv_lclif_ipaddr (s, lp); build_link_subtlv_rmtif_ipaddr (s, lp); build_link_subtlv_te_metric (s, lp); build_link_subtlv_max_bw (s, lp); build_link_subtlv_max_rsv_bw (s, lp); build_link_subtlv_unrsv_bw (s, lp); build_link_subtlv_rsc_clsclr (s, lp); return; } static void ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp) { /* * The router address TLV is type 1, and ... * It must appear in exactly one * Traffic Engineering LSA originated by a router. */ build_router_tlv (s); /* * Only one Link TLV shall be carried in each LSA, allowing for fine * granularity changes in topology. */ build_link_tlv (s, lp); return; } /* Create new opaque-LSA. */ static struct ospf_lsa * ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) { struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new = NULL; u_char options, lsa_type; struct in_addr lsa_id; u_int32_t tmp; u_int16_t length; /* Create a stream for LSA. */ if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?"); goto out; } lsah = (struct lsa_header *) STREAM_DATA (s); options = LSA_OPTIONS_GET (area); options |= LSA_OPTIONS_NSSA_GET (area); options |= OSPF_OPTION_O; /* Don't forget this :-) */ lsa_type = OSPF_OPAQUE_AREA_LSA; tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); lsa_id.s_addr = htonl (tmp); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); /* Set opaque-LSA header fields. */ lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); /* Set opaque-LSA body fields. */ ospf_mpls_te_lsa_body_set (s, lp); /* Set length. */ length = stream_get_endp (s); lsah->length = htons (length); /* Now, create an OSPF LSA instance. */ if ((new = ospf_lsa_new ()) == NULL) { zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); stream_free (s); goto out; } if ((new->data = ospf_lsa_data_new (length)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_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 linkparameter entry has associated LSA. */ lp->flags |= LPFLG_LSA_ENGAGED; /* Update new LSA origination count. */ area->ospf->lsa_originate_count++; /* Flood new LSA through area. */ ospf_flood_through_area (area, NULL/*nbr*/, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { char area_id[INET_ADDRSTRLEN]; strcpy (area_id, inet_ntoa (area->area_id)); zlog_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 (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: MPLS-TE is disabled now."); rc = 0; /* This is not an error case. */ goto out; } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if (lp->area == NULL) continue; if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) continue; if (lp->flags & LPFLG_LSA_ENGAGED) { if (lp->flags & LPFLG_LSA_FORCED_REFRESH) { lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } continue; } if (! is_mandated_params_set (lp)) { zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this area and Link. */ if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) goto out; } rc = 0; out: return rc; } static 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_lsa *new = NULL; if (OspfMplsTE.status == disabled) { /* * This LSA must have flushed before due to MPLS-TE status change. * It seems a slip among routers in the routing domain. */ zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } /* At first, resolve lsa/lp relationship. */ if ((lp = lookup_linkparams_by_instance (lsa)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?"); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE (lsa)) { lp->flags &= ~LPFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (lsa); goto out; } /* Create new Opaque-LSA/MPLS-TE instance. */ if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); goto out; } new->data->ls_seqnum = lsa_seqnum_increment (lsa); /* Install this LSA into LSDB. */ /* Given "lsa" will be freed in the next function. */ if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Flood updated LSA through area. */ ospf_flood_through_area (area, NULL/*nbr*/, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_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; } static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode opcode) { struct ospf_lsa lsa; struct lsa_header lsah; u_int32_t tmp; memset (&lsa, 0, sizeof (lsa)); memset (&lsah, 0, sizeof (lsah)); lsa.area = lp->area; lsa.data = &lsah; lsah.type = OSPF_OPAQUE_AREA_LSA; tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); lsah.id.s_addr = htonl (tmp); switch (opcode) { case REORIGINATE_PER_AREA: ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); break; case REFRESH_THIS_LSA: ospf_opaque_lsa_refresh_schedule (&lsa); break; case FLUSH_THIS_LSA: lp->flags &= ~LPFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (&lsa); break; default: zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode); break; } return; } /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ static u_int16_t show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) { struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; if (vty != NULL) vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); else zlog_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; ntohf (&top->value, &fval); 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; ntohf (&top->value, &fval); 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 fval; int i; top = (struct te_link_subtlv_unrsv_bw *) tlvh; for (i = 0; i < 8; i++) { ntohf (&top->value[i], &fval); if (vty != NULL) vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); else zlog_debug (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); } return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_rsc_clsclr *top; top = (struct te_link_subtlv_rsc_clsclr *) tlvh; if (vty != NULL) vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); else zlog_debug (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) { if (vty != NULL) vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); else zlog_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; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return sum; } static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *) lsa->data; struct te_tlv_header *tlvh, *next; u_int16_t sum, total; u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh, u_int16_t subtotal, u_int16_t total) = NULL; sum = 0; total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; for (tlvh = TLV_HDR_TOP (lsah); sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) { if (subfunc != NULL) { sum = (* subfunc)(vty, tlvh, sum, total); next = (struct te_tlv_header *)((char *) tlvh + sum); subfunc = NULL; continue; } next = NULL; switch (ntohs (tlvh->type)) { case TE_TLV_ROUTER_ADDR: sum += show_vty_router_addr (vty, tlvh); break; case TE_TLV_LINK: sum += show_vty_link_header (vty, tlvh); subfunc = ospf_mpls_te_show_link_subtlv; next = tlvh + 1; break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return; } static void ospf_mpls_te_config_write_router (struct vty *vty) { if (OspfMplsTE.status == enabled) { vty_out (vty, " mpls-te%s", VTY_NEWLINE); vty_out (vty, " mpls-te router-address %s%s", inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); } return; } static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; if ((OspfMplsTE.status == enabled) && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { float fval; int i; vty_out (vty, " mpls-te link metric %u%s", (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); ntohf (&lp->max_bw.value, &fval); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); ntohf (&lp->max_rsv_bw.value, &fval); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); for (i = 0; i < 8; i++) { ntohf (&lp->unrsv_bw.value[i], &fval); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link unrsv-bw %d %g%s", i, fval, VTY_NEWLINE); } vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); } return; } /*------------------------------------------------------------------------* * Followings are vty command functions. *------------------------------------------------------------------------*/ DEFUN (mpls_te, mpls_te_cmd, "mpls-te", "Configure MPLS-TE parameters\n" "Enable the MPLS-TE functionality\n") { struct listnode *node, *nnode; 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; /* * Following code is intended to handle two cases; * * 1) MPLS-TE was disabled at startup time, but now become enabled. * 2) MPLS-TE was once enabled then disabled, and now enabled again. */ for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) initialize_linkparams (lp); ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); return CMD_SUCCESS; } ALIAS (mpls_te, mpls_te_on_cmd, "mpls-te on", "Configure MPLS-TE parameters\n" "Enable the MPLS-TE functionality\n") DEFUN (no_mpls_te, no_mpls_te_cmd, "no mpls-te", NO_STR "Configure MPLS-TE parameters\n" "Disable the MPLS-TE functionality\n") { 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 (lp->area != NULL) if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); return CMD_SUCCESS; } DEFUN (mpls_te_router_addr, mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", "MPLS-TE specific commands\n" "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") { struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; struct in_addr value; if (! inet_aton (argv[0], &value)) { vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } if (ntohs (ra->header.type) == 0 || ntohl (ra->value.s_addr) != ntohl (value.s_addr)) { 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) continue; if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) { need_to_reoriginate = 1; break; } } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if (lp->area == NULL) continue; if (need_to_reoriginate) lp->flags |= LPFLG_LSA_FORCED_REFRESH; else ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } if (need_to_reoriginate) ospf_mpls_te_foreach_area ( ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); } out: return CMD_SUCCESS; } DEFUN (mpls_te_link_metric, mpls_te_link_metric_cmd, "mpls-te link metric <0-4294967295>", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Link metric for MPLS-TE purpose\n" "Metric\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; u_int32_t value; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } value = strtoul (argv[0], NULL, 10); if (ntohs (lp->te_metric.header.type) == 0 || ntohl (lp->te_metric.value) != value) { set_linkparams_te_metric (lp, value); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_maxbw, mpls_te_link_maxbw_cmd, "mpls-te link max-bw BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Maximum bandwidth that can be used\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; float f1, f2; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } ntohf (&lp->max_bw.value, &f1); if (sscanf (argv[0], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->max_bw.header.type) == 0 || f1 != f2) { set_linkparams_max_bw (lp, &f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_max_rsv_bw, mpls_te_link_max_rsv_bw_cmd, "mpls-te link max-rsv-bw BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Maximum bandwidth that may be reserved\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; float f1, f2; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } ntohf (&lp->max_rsv_bw.value, &f1); if (sscanf (argv[0], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->max_rsv_bw.header.type) == 0 || f1 != f2) { set_linkparams_max_rsv_bw (lp, &f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_unrsv_bw, mpls_te_link_unrsv_bw_cmd, "mpls-te link unrsv-bw <0-7> BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Unreserved bandwidth at each priority level\n" "Priority\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; int priority; float f1, f2; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } /* We don't have to consider about range check here. */ if (sscanf (argv[0], "%d", &priority) != 1) { vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } ntohf (&lp->unrsv_bw.value [priority], &f1); if (sscanf (argv[1], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->unrsv_bw.header.type) == 0 || f1 != f2) { set_linkparams_unrsv_bw (lp, priority, &f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_rsc_clsclr, mpls_te_link_rsc_clsclr_cmd, "mpls-te link rsc-clsclr BITPATTERN", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Administrative group membership\n" "32-bit Hexadecimal value (ex. 0xa1)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; unsigned long value; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } if (sscanf (argv[0], "0x%lx", &value) != 1) { vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->rsc_clsclr.header.type) == 0 || ntohl (lp->rsc_clsclr.value) != value) { set_linkparams_rsc_clsclr (lp, value); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (show_mpls_te_router, show_mpls_te_router_cmd, "show mpls-te router", SHOW_STR "MPLS-TE information\n" "Router information\n") { if (OspfMplsTE.status == enabled) { vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); if (ntohs (OspfMplsTE.router_addr.header.type) != 0) show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); else if (vty != NULL) vty_out (vty, " N/A%s", VTY_NEWLINE); } return CMD_SUCCESS; } static void show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; struct te_tlv_header *tlvh; if ((OspfMplsTE.status == enabled) && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { vty_out (vty, "-- MPLS-TE link parameters for %s --%s", ifp->name, VTY_NEWLINE); show_vty_link_subtlv_link_type (vty, &lp->link_type.header); show_vty_link_subtlv_link_id (vty, &lp->link_id.header); if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); } else { vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", ifp->name, VTY_NEWLINE); } return; } DEFUN (show_mpls_te_link, show_mpls_te_link_cmd, "show mpls-te interface [INTERFACE]", SHOW_STR "MPLS-TE information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; 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_mpls_te_router_cmd); install_element (VIEW_NODE, &show_mpls_te_link_cmd); install_element (ENABLE_NODE, &show_mpls_te_router_cmd); install_element (ENABLE_NODE, &show_mpls_te_link_cmd); install_element (OSPF_NODE, &mpls_te_cmd); install_element (OSPF_NODE, &no_mpls_te_cmd); install_element (OSPF_NODE, &mpls_te_on_cmd); install_element (OSPF_NODE, &mpls_te_router_addr_cmd); install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); return; } #endif /* HAVE_OSPF_TE */ quagga-0.99.22.4/ospfd/ospf_te.h0000644000175000017500000001337112177450262013163 00000000000000/* * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_MPLS_TE_H #define _ZEBRA_OSPF_MPLS_TE_H /* * Opaque LSA's link state ID for Traffic Engineering is * structured as follows. * * 24 16 8 0 * +--------+--------+--------+--------+ * | 1 | MBZ |........|........| * +--------+--------+--------+--------+ * |<-Type->||<-- Instance --->| * * * Type: IANA has assigned '1' for Traffic Engineering. * MBZ: Reserved, must be set to zero. * Instance: User may select an arbitrary 16-bit value. * */ #define MAX_LEGAL_TE_INSTANCE_NUM (0xffff) /* * 24 16 8 0 * +--------+--------+--------+--------+ --- * | LS age |Options | 10 | A * +--------+--------+--------+--------+ | * | 1 | 0 | Instance | | * +--------+--------+--------+--------+ | * | Advertising router | | Standard (Opaque) LSA header; * +--------+--------+--------+--------+ | Only type-10 is used. * | LS sequence number | | * +--------+--------+--------+--------+ | * | LS checksum | Length | V * +--------+--------+--------+--------+ --- * | Type | Length | A * +--------+--------+--------+--------+ | TLV part for TE; Values might be * | Values ... | V structured as a set of sub-TLVs. * +--------+--------+--------+--------+ --- */ /* * Following section defines TLV (tag, length, value) structures, * used for Traffic Engineering. */ struct te_tlv_header { u_int16_t type; /* TE_TLV_XXX (see below) */ u_int16_t length; /* Value portion only, in octets */ }; #define TLV_HDR_SIZE \ (sizeof (struct te_tlv_header)) #define TLV_BODY_SIZE(tlvh) \ (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))) #define TLV_SIZE(tlvh) \ (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) #define TLV_HDR_TOP(lsah) \ (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) #define TLV_HDR_NEXT(tlvh) \ (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) /* * Following section defines TLV body parts. */ /* Router Address TLV *//* Mandatory */ #define TE_TLV_ROUTER_ADDR 1 struct te_tlv_router_addr { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; }; /* Link TLV */ #define TE_TLV_LINK 2 struct te_tlv_link { struct te_tlv_header header; /* A set of link-sub-TLVs will follow. */ }; /* Link Type Sub-TLV *//* Mandatory */ #define TE_LINK_SUBTLV_LINK_TYPE 1 struct te_link_subtlv_link_type { struct te_tlv_header header; /* Value length is 1 octet. */ struct { #define LINK_TYPE_SUBTLV_VALUE_PTP 1 #define LINK_TYPE_SUBTLV_VALUE_MA 2 u_char value; u_char padding[3]; } link_type; }; /* Link Sub-TLV: Link ID *//* Mandatory */ #define TE_LINK_SUBTLV_LINK_ID 2 struct te_link_subtlv_link_id { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Same as router-lsa's link-id. */ }; /* Link Sub-TLV: Local Interface IP Address *//* Optional */ #define TE_LINK_SUBTLV_LCLIF_IPADDR 3 struct te_link_subtlv_lclif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Local IP address(es). */ }; /* Link Sub-TLV: Remote Interface IP Address *//* Optional */ #define TE_LINK_SUBTLV_RMTIF_IPADDR 4 struct te_link_subtlv_rmtif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Neighbor's IP address(es). */ }; /* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ #define TE_LINK_SUBTLV_TE_METRIC 5 struct te_link_subtlv_te_metric { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Link metric for TE purpose. */ }; /* Link Sub-TLV: Maximum Bandwidth *//* Optional */ #define TE_LINK_SUBTLV_MAX_BW 6 struct te_link_subtlv_max_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; /* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ #define TE_LINK_SUBTLV_MAX_RSV_BW 7 struct te_link_subtlv_max_rsv_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; /* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ #define TE_LINK_SUBTLV_UNRSV_BW 8 struct te_link_subtlv_unrsv_bw { struct te_tlv_header header; /* Value length is 32 octets. */ float value[8]; /* One for each priority level. */ }; /* Link Sub-TLV: Resource Class/Color *//* Optional */ #define TE_LINK_SUBTLV_RSC_CLSCLR 9 struct te_link_subtlv_rsc_clsclr { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Admin. group membership. */ }; /* Here are "non-official" architechtual constants. */ #define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ /* Prototypes. */ extern int ospf_mpls_te_init (void); extern void ospf_mpls_te_term (void); #endif /* _ZEBRA_OSPF_MPLS_TE_H */ quagga-0.99.22.4/ospfd/ospf_vty.c0000644000175000017500000075532112177450262013400 00000000000000/* 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. */ static 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 (struct ospf *ospf, struct interface *ifp, struct in_addr addr, struct ospf_if_params *params, u_char value) { 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); } else { if (value != ospf->passive_interface_default) SET_IF_PARAM (params, passive_interface); else UNSET_IF_PARAM (params, passive_interface); } } 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 (ospf, ifp, addr, 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 (ospf, ifp, addr, 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); } } 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 = 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" "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); } return CMD_SUCCESS; } DEFUN (no_ospf_compatible_rfc1583, no_ospf_compatible_rfc1583_cmd, "no compatible rfc1583", NO_STR "OSPF compatibility list\n" "compatible with RFC 1583\n") { struct ospf *ospf = vty->index; if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { UNSET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); ospf_spf_calculate_schedule (ospf); } return CMD_SUCCESS; } ALIAS (ospf_compatible_rfc1583, ospf_rfc1583_flag_cmd, "ospf rfc1583compatibility", "OSPF specific commands\n" "Enable the RFC1583Compatibility flag\n") ALIAS (no_ospf_compatible_rfc1583, no_ospf_rfc1583_flag_cmd, "no ospf rfc1583compatibility", NO_STR "OSPF specific commands\n" "Disable the RFC1583Compatibility flag\n") 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_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); #ifdef HAVE_OPAQUE_LSA 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); #endif /* HAVE_OPAQUE_LSA */ 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); #ifdef HAVE_OPAQUE_LSA vty_out (vty, " OpaqueCapability flag is %s%s%s", CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? "enabled" : "disabled", IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf->opaque) ? " (origination blocked)" : "", VTY_NEWLINE); #endif /* HAVE_OPAQUE_LSA */ /* Show 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); } 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); #ifdef HAVE_OPAQUE_LSA 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); #endif /* HAVE_OPAQUE_LSA */ /* 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ default: break; } vty_out (vty, VTY_NEWLINE); } return 0; } 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", #ifdef HAVE_OPAQUE_LSA "Type-8 LSA", "Link-Local Opaque-LSA", "Area-Local Opaque-LSA", "AS-external Opaque-LSA", #endif /* HAVE_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", #ifdef HAVE_OPAQUE_LSA " --- type-8 ---", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", #endif /* HAVE_OPAQUE_LSA */ }; 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, i, type; len = ntohs (rl->header.length) - 4; for (i = 0; i < ntohs (rl->links) && len > 0; len -= 12, i++) { type = rl->link[i].type; vty_out (vty, " Link connected to: %s%s", link_type_desc[type], VTY_NEWLINE); vty_out (vty, " (Link ID) %s: %s%s", link_id_desc[type], inet_ntoa (rl->link[i].link_id), VTY_NEWLINE); vty_out (vty, " (Link Data) %s: %s%s", link_data_desc[type], inet_ntoa (rl->link[i].link_data), VTY_NEWLINE); vty_out (vty, " Number of TOS metrics: 0%s", VTY_NEWLINE); vty_out (vty, " TOS 0 Metric: %d%s", ntohs (rl->link[i].metric), VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } } /* Show router-LSA detail information. */ 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: %u%s%s", 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: %u%s%s", 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; } #ifdef HAVE_OPAQUE_LSA 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; } #endif /* HAVE_OPAQUE_LSA */ int (*show_function[])(struct vty *, struct ospf_lsa *) = { NULL, show_router_lsa_detail, show_network_lsa_detail, show_summary_lsa_detail, show_summary_asbr_lsa_detail, show_as_external_lsa_detail, show_func_dummy, show_as_nssa_lsa_detail, /* almost same as external */ #ifdef HAVE_OPAQUE_LSA NULL, /* type-8 */ show_opaque_lsa_detail, show_opaque_lsa_detail, show_opaque_lsa_detail, #endif /* HAVE_OPAQUE_LSA */ }; 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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); show_lsa_detail_proc (vty, AS_LSDB (ospf, type), id, adv_router); break; default: for (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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); show_lsa_detail_adv_router_proc (vty, AS_LSDB (ospf, type), adv_router); break; default: for (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: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ continue; default: break; } if (ospf_lsdb_count_self (area->lsdb, type) > 0 || (!self && ospf_lsdb_count (area->lsdb, type) > 0)) { vty_out (vty, " %s (Area %s)%s%s", show_database_desc[type], ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE); LSDB_LOOP (AREA_LSDB (area, type), rn, lsa) show_lsa_summary (vty, lsa, self); vty_out (vty, "%s", VTY_NEWLINE); } } } for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) { switch (type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ break; default: continue; } if (ospf_lsdb_count_self (ospf->lsdb, type) || (!self && ospf_lsdb_count (ospf->lsdb, type))) { vty_out (vty, " %s%s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE); LSDB_LOOP (AS_LSDB (ospf, type), rn, lsa) show_lsa_summary (vty, lsa, self); vty_out (vty, "%s", VTY_NEWLINE); } } vty_out (vty, "%s", VTY_NEWLINE); } static void show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) { struct route_node *rn; struct ospf_lsa *lsa; 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" #ifdef HAVE_OPAQUE_LSA #define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AS_DESC "Link AS Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_CMD_STR "|opaque-link|opaque-area|opaque-as" #else /* HAVE_OPAQUE_LSA */ #define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "" #define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "" #define OSPF_LSA_TYPE_OPAQUE_AS_DESC "" #define OSPF_LSA_TYPE_OPAQUE_CMD_STR "" #endif /* HAVE_OPAQUE_LSA */ #define OSPF_LSA_TYPES_CMD_STR \ "asbr-summary|external|network|router|summary" \ OSPF_LSA_TYPE_NSSA_CMD_STR \ OSPF_LSA_TYPE_OPAQUE_CMD_STR #define OSPF_LSA_TYPES_DESC \ "ASBR summary link states\n" \ "External link states\n" \ "Network link states\n" \ "Router link states\n" \ "Network summary link states\n" \ OSPF_LSA_TYPE_NSSA_DESC \ OSPF_LSA_TYPE_OPAQUE_LINK_DESC \ OSPF_LSA_TYPE_OPAQUE_AREA_DESC \ OSPF_LSA_TYPE_OPAQUE_AS_DESC DEFUN (show_ip_ospf_database, show_ip_ospf_database_cmd, "show ip ospf database", SHOW_STR IP_STR "OSPF information\n" "Database summary\n") { struct ospf *ospf; int type, ret; struct in_addr id, adv_router; ospf = ospf_lookup (); if (ospf == NULL) { 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; } #ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; #endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; /* `show ip ospf database LSA'. */ if (argc == 1) show_lsa_detail (vty, ospf, type, NULL, NULL); else if (argc >= 2) { ret = inet_aton (argv[1], &id); if (!ret) return CMD_WARNING; /* `show ip ospf database LSA ID'. */ if (argc == 2) show_lsa_detail (vty, ospf, type, &id, NULL); /* `show ip ospf database LSA ID adv-router ADV_ROUTER'. */ else if (argc == 3) { if (strncmp (argv[2], "s", 1) == 0) adv_router = ospf->router_id; else { ret = inet_aton (argv[2], &adv_router); if (!ret) return CMD_WARNING; } show_lsa_detail (vty, ospf, type, &id, &adv_router); } } return CMD_SUCCESS; } ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR "|max-age|self-originate)", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "LSAs in MaxAge list\n" "Self-originated link states\n") ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_id_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n") ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_id_adv_router_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D adv-router A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n" "Advertising Router link states\n" "Advertising Router (as an IP address)\n") ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_id_self_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D (self-originate|)", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n" "Self-originated link states\n" "\n") DEFUN (show_ip_ospf_database_type_adv_router, show_ip_ospf_database_type_adv_router_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") adv-router A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Advertising Router link states\n" "Advertising Router (as an IP address)\n") { struct ospf *ospf; int type, ret; struct in_addr adv_router; ospf = ospf_lookup (); if (ospf == NULL) { 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; #ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; #endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; /* `show ip ospf database LSA adv-router ADV_ROUTER'. */ if (strncmp (argv[1], "s", 1) == 0) adv_router = ospf->router_id; else { ret = inet_aton (argv[1], &adv_router); if (!ret) return CMD_WARNING; } show_lsa_detail_adv_router (vty, ospf, type, &adv_router); return CMD_SUCCESS; } ALIAS (show_ip_ospf_database_type_adv_router, show_ip_ospf_database_type_self_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") (self-originate|)", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Self-originated link states\n") DEFUN (ip_ospf_authentication_args, ip_ospf_authentication_args_addr_cmd, "ip ospf authentication (null|message-digest) A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } /* Handle null authentication */ if ( argv[0][0] == 'n' ) { SET_IF_PARAM (params, auth_type); params->auth_type = OSPF_AUTH_NULL; return CMD_SUCCESS; } /* Handle message-digest authentication */ if ( argv[0][0] == 'm' ) { SET_IF_PARAM (params, auth_type); params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; return CMD_SUCCESS; } vty_out (vty, "You shouldn't get here!%s", VTY_NEWLINE); return CMD_WARNING; } ALIAS (ip_ospf_authentication_args, ip_ospf_authentication_args_cmd, "ip ospf authentication (null|message-digest)", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n") DEFUN (ip_ospf_authentication, ip_ospf_authentication_addr_cmd, "ip ospf authentication A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[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 A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; struct ospf_interface *oi; struct route_node *rn; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, v_wait); params->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; 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_cmd, "no ip ospf dead-interval", NO_STR "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n") ALIAS (no_ip_ospf_dead_interval, no_ospf_dead_interval_cmd, "no ospf dead-interval", NO_STR "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n") DEFUN (ip_ospf_hello_interval, ip_ospf_hello_interval_addr_cmd, "ip ospf hello-interval <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n" "Address of interface") { struct interface *ifp = vty->index; u_int32_t seconds; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); seconds = strtol (argv[0], NULL, 10); /* HelloInterval range is <1-65535>. */ if (seconds < 1 || seconds > 65535) { vty_out (vty, "Hello Interval is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, v_hello); params->v_hello = seconds; return CMD_SUCCESS; } ALIAS (ip_ospf_hello_interval, ip_ospf_hello_interval_cmd, "ip ospf hello-interval <1-65535>", "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") ALIAS (ip_ospf_hello_interval, ospf_hello_interval_cmd, "ospf hello-interval <1-65535>", "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") DEFUN (no_ip_ospf_hello_interval, no_ip_ospf_hello_interval_addr_cmd, "no ip ospf hello-interval A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, v_hello); params->v_hello = OSPF_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_cmd, "no ip ospf hello-interval", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n") ALIAS (no_ip_ospf_hello_interval, no_ospf_hello_interval_cmd, "no ospf hello-interval", NO_STR "OSPF interface commands\n" "Time between HELLO packets\n") DEFUN (ip_ospf_network, ip_ospf_network_cmd, "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", "IP Information\n" "OSPF interface commands\n" "Network type\n" "Specify OSPF broadcast multi-access network\n" "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF point-to-point network\n") { struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; struct route_node *rn; if (strncmp (argv[0], "b", 1) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; else if (strncmp (argv[0], "n", 1) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_NBMA; else if (strncmp (argv[0], "point-to-m", 10) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT; else if (strncmp (argv[0], "point-to-p", 10) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; if (IF_DEF_PARAMS (ifp)->type == old_type) return CMD_SUCCESS; SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (!oi) continue; oi->type = IF_DEF_PARAMS (ifp)->type; if (oi->state > ISM_Down) { OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); } } return CMD_SUCCESS; } ALIAS (ip_ospf_network, ospf_network_cmd, "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", "OSPF interface commands\n" "Network type\n" "Specify OSPF broadcast multi-access network\n" "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF point-to-point network\n") DEFUN (no_ip_ospf_network, no_ip_ospf_network_cmd, "no ip ospf network", NO_STR "IP Information\n" "OSPF interface commands\n" "Network type\n") { struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; struct route_node *rn; IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp); if (IF_DEF_PARAMS (ifp)->type == old_type) return CMD_SUCCESS; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (!oi) continue; oi->type = IF_DEF_PARAMS (ifp)->type; if (oi->state > ISM_Down) { OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); } } return CMD_SUCCESS; } ALIAS (no_ip_ospf_network, no_ospf_network_cmd, "no ospf network", NO_STR "OSPF interface commands\n" "Network type\n") DEFUN (ip_ospf_priority, ip_ospf_priority_addr_cmd, "ip ospf priority <0-255> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Priority\n" "Address of interface") { struct interface *ifp = vty->index; 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 (ospf_redistribute_source_metric_type, ospf_redistribute_source_metric_type_routemap_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; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ if (argc >= 2) if (!str2metric (argv[1], &metric)) return CMD_WARNING; /* Get metric type. */ if (argc >= 3) if (!str2metric_type (argv[2], &type)) return CMD_WARNING; if (argc == 4) ospf_routemap_set (ospf, source, argv[3]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, type, metric); } ALIAS (ospf_redistribute_source_metric_type, ospf_redistribute_source_metric_type_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric <0-16777214> metric-type (1|2)", 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") ALIAS (ospf_redistribute_source_metric_type, ospf_redistribute_source_metric_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric <0-16777214>", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" "OSPF default metric\n") DEFUN (ospf_redistribute_source_type_metric, ospf_redistribute_source_type_metric_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric-type (1|2) metric <0-16777214> route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "OSPF exterior metric type for redistributed routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Metric for redistributed routes\n" "OSPF default metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int source; int type = -1; int metric = -1; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ if (argc >= 2) if (!str2metric_type (argv[1], &type)) return CMD_WARNING; /* Get metric type. */ if (argc >= 3) if (!str2metric (argv[2], &metric)) return CMD_WARNING; if (argc == 4) ospf_routemap_set (ospf, source, argv[3]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, type, metric); } ALIAS (ospf_redistribute_source_type_metric, ospf_redistribute_source_type_metric_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric-type (1|2) metric <0-16777214>", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "OSPF exterior metric type for redistributed routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Metric for redistributed routes\n" "OSPF default metric\n") ALIAS (ospf_redistribute_source_type_metric, ospf_redistribute_source_type_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric-type (1|2)", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "OSPF exterior metric type for redistributed routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n") ALIAS (ospf_redistribute_source_type_metric, ospf_redistribute_source_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD, REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD) DEFUN (ospf_redistribute_source_metric_routemap, ospf_redistribute_source_metric_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric <0-16777214> route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" "OSPF default metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int source; int metric = -1; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ if (argc >= 2) if (!str2metric (argv[1], &metric)) return CMD_WARNING; if (argc == 3) ospf_routemap_set (ospf, source, argv[2]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, -1, metric); } DEFUN (ospf_redistribute_source_type_routemap, ospf_redistribute_source_type_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " metric-type (1|2) route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "OSPF exterior metric type for redistributed routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int source; int type = -1; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ if (argc >= 2) if (!str2metric_type (argv[1], &type)) return CMD_WARNING; if (argc == 3) ospf_routemap_set (ospf, source, argv[2]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, type, -1); } DEFUN (ospf_redistribute_source_routemap, ospf_redistribute_source_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int source; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; if (argc == 2) ospf_routemap_set (ospf, source, argv[1]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, -1, -1); } DEFUN (no_ospf_redistribute_source, no_ospf_redistribute_source_cmd, "no redistribute " 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_metric_type_routemap, ospf_default_information_originate_metric_type_routemap_cmd, "default-information originate metric <0-16777214> metric-type (1|2) route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int type = -1; int metric = -1; /* Get metric value. */ if (argc >= 1) if (!str2metric (argv[0], &metric)) return CMD_WARNING; /* Get metric type. */ if (argc >= 2) if (!str2metric_type (argv[1], &type)) return CMD_WARNING; if (argc == 3) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, type, metric); } ALIAS (ospf_default_information_originate_metric_type_routemap, ospf_default_information_originate_metric_type_cmd, "default-information originate metric <0-16777214> metric-type (1|2)", "Control distribution of default information\n" "Distribute a default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n") ALIAS (ospf_default_information_originate_metric_type_routemap, ospf_default_information_originate_metric_cmd, "default-information originate metric <0-16777214>", "Control distribution of default information\n" "Distribute a default route\n" "OSPF default metric\n" "OSPF metric\n") ALIAS (ospf_default_information_originate_metric_type_routemap, ospf_default_information_originate_cmd, "default-information originate", "Control distribution of default information\n" "Distribute a default route\n") /* Default information originate. */ DEFUN (ospf_default_information_originate_metric_routemap, ospf_default_information_originate_metric_routemap_cmd, "default-information originate metric <0-16777214> route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "OSPF default metric\n" "OSPF metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int metric = -1; /* Get metric value. */ if (argc >= 1) if (!str2metric (argv[0], &metric)) return CMD_WARNING; if (argc == 2) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, -1, metric); } /* Default information originate. */ DEFUN (ospf_default_information_originate_routemap, ospf_default_information_originate_routemap_cmd, "default-information originate route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; if (argc == 1) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[0]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, -1, -1); } DEFUN (ospf_default_information_originate_type_metric_routemap, ospf_default_information_originate_type_metric_routemap_cmd, "default-information originate metric-type (1|2) metric <0-16777214> route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "OSPF default metric\n" "OSPF metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int type = -1; int metric = -1; /* Get metric type. */ if (argc >= 1) if (!str2metric_type (argv[0], &type)) return CMD_WARNING; /* Get metric value. */ if (argc >= 2) if (!str2metric (argv[1], &metric)) return CMD_WARNING; if (argc == 3) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, type, metric); } ALIAS (ospf_default_information_originate_type_metric_routemap, ospf_default_information_originate_type_metric_cmd, "default-information originate metric-type (1|2) metric <0-16777214>", "Control distribution of default information\n" "Distribute a default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "OSPF default metric\n" "OSPF metric\n") ALIAS (ospf_default_information_originate_type_metric_routemap, ospf_default_information_originate_type_cmd, "default-information originate metric-type (1|2)", "Control distribution of default information\n" "Distribute a default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n") DEFUN (ospf_default_information_originate_type_routemap, ospf_default_information_originate_type_routemap_cmd, "default-information originate metric-type (1|2) route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int type = -1; /* Get metric type. */ if (argc >= 1) if (!str2metric_type (argv[0], &type)) return CMD_WARNING; if (argc == 2) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ZEBRA, type, -1); } DEFUN (ospf_default_information_originate_always_metric_type_routemap, ospf_default_information_originate_always_metric_type_routemap_cmd, "default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int type = -1; int metric = -1; /* Get metric value. */ if (argc >= 1) if (!str2metric (argv[0], &metric)) return CMD_WARNING; /* Get metric type. */ if (argc >= 2) if (!str2metric_type (argv[1], &type)) return CMD_WARNING; if (argc == 3) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, type, metric); } ALIAS (ospf_default_information_originate_always_metric_type_routemap, ospf_default_information_originate_always_metric_type_cmd, "default-information originate always metric <0-16777214> metric-type (1|2)", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n") ALIAS (ospf_default_information_originate_always_metric_type_routemap, ospf_default_information_originate_always_metric_cmd, "default-information originate always metric <0-16777214>", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n") ALIAS (ospf_default_information_originate_always_metric_type_routemap, ospf_default_information_originate_always_cmd, "default-information originate always", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n") DEFUN (ospf_default_information_originate_always_metric_routemap, ospf_default_information_originate_always_metric_routemap_cmd, "default-information originate always metric <0-16777214> route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF default metric\n" "OSPF metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int metric = -1; /* Get metric value. */ if (argc >= 1) if (!str2metric (argv[0], &metric)) return CMD_WARNING; if (argc == 2) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, -1, metric); } DEFUN (ospf_default_information_originate_always_routemap, ospf_default_information_originate_always_routemap_cmd, "default-information originate always route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; if (argc == 1) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[0]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, -1, -1); } DEFUN (ospf_default_information_originate_always_type_metric_routemap, ospf_default_information_originate_always_type_metric_routemap_cmd, "default-information originate always metric-type (1|2) metric <0-16777214> route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "OSPF default metric\n" "OSPF metric\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int type = -1; int metric = -1; /* Get metric type. */ if (argc >= 1) if (!str2metric_type (argv[0], &type)) return CMD_WARNING; /* Get metric value. */ if (argc >= 2) if (!str2metric (argv[1], &metric)) return CMD_WARNING; if (argc == 3) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[2]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, type, metric); } ALIAS (ospf_default_information_originate_always_type_metric_routemap, ospf_default_information_originate_always_type_metric_cmd, "default-information originate always metric-type (1|2) metric <0-16777214>", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "OSPF default metric\n" "OSPF metric\n") ALIAS (ospf_default_information_originate_always_type_metric_routemap, ospf_default_information_originate_always_type_cmd, "default-information originate always metric-type (1|2)", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n") DEFUN (ospf_default_information_originate_always_type_routemap, ospf_default_information_originate_always_type_routemap_cmd, "default-information originate always metric-type (1|2) route-map WORD", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int type = -1; /* Get metric type. */ if (argc >= 1) if (!str2metric_type (argv[0], &type)) return CMD_WARNING; if (argc == 2) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[1]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, DEFAULT_ORIGINATE_ALWAYS, type, -1); } DEFUN (no_ospf_default_information_originate, no_ospf_default_information_originate_cmd, "no default-information originate", NO_STR "Control distribution of default information\n" "Distribute a default route\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p; 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", NO_STR "Define an administrative distance\n" "OSPF Administrative distance\n" "OSPF Distance\n") { struct ospf *ospf = vty->index; ospf->distance_intra = 0; ospf->distance_inter = 0; ospf->distance_external = 0; return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_intra, ospf_distance_ospf_intra_cmd, "distance ospf intra-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_intra = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_intra_inter, ospf_distance_ospf_intra_inter_cmd, "distance ospf intra-area <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_intra = atoi (argv[0]); ospf->distance_inter = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_intra_external, ospf_distance_ospf_intra_external_cmd, "distance ospf intra-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; ospf->distance_intra = atoi (argv[0]); ospf->distance_external = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_intra_inter_external, ospf_distance_ospf_intra_inter_external_cmd, "distance ospf intra-area <1-255> inter-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; ospf->distance_intra = atoi (argv[0]); ospf->distance_inter = atoi (argv[1]); ospf->distance_external = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_intra_external_inter, ospf_distance_ospf_intra_external_inter_cmd, "distance ospf intra-area <1-255> external <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "External routes\n" "Distance for external routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_intra = atoi (argv[0]); ospf->distance_external = atoi (argv[1]); ospf->distance_inter = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_inter, ospf_distance_ospf_inter_cmd, "distance ospf inter-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_inter = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_inter_intra, ospf_distance_ospf_inter_intra_cmd, "distance ospf inter-area <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_inter = atoi (argv[0]); ospf->distance_intra = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_inter_external, ospf_distance_ospf_inter_external_cmd, "distance ospf inter-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; ospf->distance_inter = atoi (argv[0]); ospf->distance_external = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_inter_intra_external, ospf_distance_ospf_inter_intra_external_cmd, "distance ospf inter-area <1-255> intra-area <1-255> external <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "Intra-area routes\n" "Distance for intra-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; ospf->distance_inter = atoi (argv[0]); ospf->distance_intra = atoi (argv[1]); ospf->distance_external = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_inter_external_intra, ospf_distance_ospf_inter_external_intra_cmd, "distance ospf inter-area <1-255> external <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_inter = atoi (argv[0]); ospf->distance_external = atoi (argv[1]); ospf->distance_intra = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_external, ospf_distance_ospf_external_cmd, "distance ospf external <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; ospf->distance_external = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_external_intra, ospf_distance_ospf_external_intra_cmd, "distance ospf external <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "External routes\n" "Distance for external routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_external = atoi (argv[0]); ospf->distance_intra = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_external_inter, ospf_distance_ospf_external_inter_cmd, "distance ospf external <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "External routes\n" "Distance for external routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_external = atoi (argv[0]); ospf->distance_inter = atoi (argv[1]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_external_intra_inter, ospf_distance_ospf_external_intra_inter_cmd, "distance ospf external <1-255> intra-area <1-255> inter-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "External routes\n" "Distance for external routes\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_external = atoi (argv[0]); ospf->distance_intra = atoi (argv[1]); ospf->distance_inter = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_ospf_external_inter_intra, ospf_distance_ospf_external_inter_intra_cmd, "distance ospf external <1-255> inter-area <1-255> intra-area <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n" "External routes\n" "Distance for external routes\n" "Inter-area routes\n" "Distance for inter-area routes\n" "Intra-area routes\n" "Distance for intra-area routes\n") { struct ospf *ospf = vty->index; ospf->distance_external = atoi (argv[0]); ospf->distance_inter = atoi (argv[1]); ospf->distance_intra = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_source, ospf_distance_source_cmd, "distance <1-255> A.B.C.D/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") { struct ospf *ospf = vty->index; ospf_distance_set (vty, ospf, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (no_ospf_distance_source, no_ospf_distance_source_cmd, "no distance <1-255> A.B.C.D/M", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n") { struct ospf *ospf = vty->index; ospf_distance_unset (vty, ospf, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (ospf_distance_source_access_list, ospf_distance_source_access_list_cmd, "distance <1-255> A.B.C.D/M WORD", "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { struct ospf *ospf = vty->index; ospf_distance_set (vty, ospf, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (no_ospf_distance_source_access_list, no_ospf_distance_source_access_list_cmd, "no distance <1-255> A.B.C.D/M WORD", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { struct ospf *ospf = vty->index; ospf_distance_unset (vty, ospf, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } 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); } /* 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); #ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_if (vty, ifp); #endif /* HAVE_OPAQUE_LSA */ } 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 && zclient->redist[type]) { 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); } /* 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); #ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_router (vty, ospf); #endif /* HAVE_OPAQUE_LSA */ } return write; } void ospf_vty_show_init (void) { /* "show ip ospf" commands. */ install_element (VIEW_NODE, &show_ip_ospf_cmd); install_element (ENABLE_NODE, &show_ip_ospf_cmd); /* "show ip ospf database" commands. */ install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_cmd); /* "show ip ospf interface" commands. */ install_element (VIEW_NODE, &show_ip_ospf_interface_cmd); install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd); /* "show ip ospf neighbor" commands. */ install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd); /* "show ip ospf route" commands. */ install_element (VIEW_NODE, &show_ip_ospf_route_cmd); install_element (ENABLE_NODE, &show_ip_ospf_route_cmd); install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd); install_element (ENABLE_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); /* "ip ospf hello-interval" commands. */ install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd); /* "ip ospf network" commands. */ install_element (INTERFACE_NODE, &ip_ospf_network_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd); /* "ip ospf priority" commands. */ install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_priority_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd); /* "ip ospf retransmit-interval" commands. */ install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd); /* "ip ospf transmit-delay" commands. */ install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd); /* These commands are compatibitliy for previous version. */ install_element (INTERFACE_NODE, &ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd); install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd); install_element (INTERFACE_NODE, &ospf_cost_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_type_metric_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_type_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_metric_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_metric_type_routemap_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_type_metric_routemap_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_metric_routemap_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_type_routemap_cmd); install_element (OSPF_NODE, &ospf_redistribute_source_routemap_cmd); install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd); install_element (OSPF_NODE, &ospf_distribute_list_out_cmd); install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_metric_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_type_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_type_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_metric_type_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_metric_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_type_metric_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_type_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_type_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_metric_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_type_metric_routemap_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_always_type_routemap_cmd); install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd); install_element (OSPF_NODE, &ospf_default_metric_cmd); install_element (OSPF_NODE, &no_ospf_default_metric_cmd); install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd); install_element (OSPF_NODE, &ospf_distance_cmd); install_element (OSPF_NODE, &no_ospf_distance_cmd); install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_intra_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_intra_inter_external_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_intra_external_inter_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_inter_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_inter_intra_external_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_inter_external_intra_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_external_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_external_intra_inter_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_external_inter_intra_cmd); #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 }; /* 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); /* 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-0.99.22.4/ospfd/ospf_vty.h0000644000175000017500000000546012000052240013350 00000000000000/* 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); #endif /* _QUAGGA_OSPF_VTY_H */ quagga-0.99.22.4/ospfd/ospf_zebra.c0000644000175000017500000010503112177450262013644 00000000000000/* * 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 */ /* 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) { 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) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); 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) { struct interface *ifp; struct stream *s; struct route_node *rn; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read (s); if (ifp == NULL) return 0; if (if_is_up (ifp)) zlog_warn ("Zebra: got delete of %s, but interface is still up", ifp->name); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_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) { 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) { struct interface *ifp; struct ospf_interface *oi; struct route_node *rn; ifp = zebra_interface_if_lookup (zclient->ibuf); if (ifp == NULL) return 0; /* Interface is already up. */ if (if_is_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) { struct interface *ifp; struct ospf_interface *oi; struct route_node *node; ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_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) { struct connected *c; c = zebra_interface_address_read (command, zclient->ibuf); 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) { 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); 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; /* 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; } 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 (zclient->redist[ZEBRA_ROUTE_OSPF]) { message = 0; flags = 0; /* OSPF pass nexthop and metric */ SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); /* Distance value. */ distance = ospf_distance_apply (p, or); if (distance) SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); /* Make packet. */ s = zclient->obuf; stream_reset (s); /* Put command, type, flags, message. */ zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD); 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); } 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 (zclient->redist[ZEBRA_ROUTE_OSPF]) { 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); 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 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); } 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 (zclient->redist[ZEBRA_ROUTE_OSPF]) { 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; 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 (zclient->redist[ZEBRA_ROUTE_OSPF]) { 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; 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)) ? zclient->default_information : zclient->redist[type]; } int ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue) { int force = 0; if (ospf_is_type_redistributed (type)) { if (mtype != ospf->dmetric[type].type) { ospf->dmetric[type].type = mtype; force = LSA_REFRESH_FORCE; } if (mvalue != ospf->dmetric[type].value) { ospf->dmetric[type].value = mvalue; force = LSA_REFRESH_FORCE; } ospf_external_lsa_refresh_type (ospf, type, force); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_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); 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); 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); 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); 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) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; struct external_info *ei; struct ospf *ospf; s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); 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); 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; */ ei = ospf_external_info_add (api.type, p, ifindex, nexthop); if (ospf->router_id.s_addr == 0) /* Set flags to generate AS-external-LSA originate event for each redistributed protocols later. */ ospf->external_origin |= (1 << api.type); else { if (ei) { if (is_prefix_default (&p)) ospf_external_lsa_refresh_default (ospf); else { struct ospf_lsa *current; current = ospf_external_info_find_lsa (ospf, &ei->p); if (!current) ospf_external_lsa_originate (ospf, ei); else if (IS_LSA_MAXAGE (current)) ospf_external_lsa_refresh (ospf, current, ei, LSA_REFRESH_FORCE); else zlog_warn ("ospf_zebra_read_ipv4() : %s already exists", inet_ntoa (p.prefix)); } } } } else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ { ospf_external_info_delete (api.type, p); if (is_prefix_default (&p)) ospf_external_lsa_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; } #define OSPF_DISTRIBUTE_UPDATE_DELAY 5 /* 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 (master, ospf_distribute_list_update_timer, (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY); } /* If access-list is updated, apply some check. */ static void ospf_filter_update (struct access_list *access) { 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), access->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), plist->name) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area)); abr_inv++; } /* Update filter-list out. */ if (PREFIX_NAME_OUT (area)) if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); abr_inv++; } } /* Schedule ABR 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; } void ospf_zebra_init () { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_OSPF); 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->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-0.99.22.4/ospfd/ospf_zebra.h0000644000175000017500000000547712177450262013666 00000000000000/* * 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 (void); #endif /* _ZEBRA_OSPF_ZEBRA_H */ quagga-0.99.22.4/ospfd/ospfd.c0000644000175000017500000012030212177450262012623 00000000000000/* 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 prefix *, struct ospf_area *, struct interface *); 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)) /* Update self-neighbor's router_id. */ oi->nbr_self->router_id = router_id; /* If AS-external-LSA is queued, then flush those LSAs. */ if (router_id_old.s_addr == 0 && ospf->external_origin) { int type; /* Originate each redistributed external route. */ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) if (ospf->external_origin & (1 << type)) thread_add_event (master, ospf_external_lsa_originate_timer, ospf, type); /* Originate Deafult. */ if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX)) thread_add_event (master, ospf_default_originate_timer, ospf, 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->default_metric = -1; new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; /* SPF timer value init. */ new->spf_delay = OSPF_SPF_DELAY_DEFAULT; new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; new->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; new->spf_hold_multiplier = 1; /* MaxAge init. */ new->maxage_delay = OSFP_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 (listhead (om->ospf)); } 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); #ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_init (ospf); #endif /* HAVE_OPAQUE_LSA */ } 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; #ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_term (ospf); #endif /* HAVE_OPAQUE_LSA */ /* 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); #ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (ospf->t_opaque_lsa_self); #endif close (ospf->fd); stream_free(ospf->ibuf); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); #endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); ospf_lsdb_delete_all (ospf->lsdb); ospf_lsdb_free (ospf->lsdb); for (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; #ifdef HAVE_OPAQUE_LSA ospf_opaque_type10_lsa_init (new); #endif /* HAVE_OPAQUE_LSA */ new->oiflist = list_new (); new->ranges = route_table_init (); if (area_id.s_addr == OSPF_AREA_BACKBONE) ospf->backbone = new; return new; } 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); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); #endif /* HAVE_OPAQUE_LSA */ ospf_lsdb_delete_all (area->lsdb); ospf_lsdb_free (area->lsdb); 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); #ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (area->t_opaque_lsa_self); #endif /* HAVE_OPAQUE_LSA */ 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 ospf_network_free (struct ospf *ospf, struct ospf_network *network) { ospf_area_check_free (ospf, network->area_id); ospf_schedule_abr_task (ospf); XFREE (MTYPE_OSPF_NETWORK, network); } int ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, struct in_addr area_id) { struct ospf_network *network; struct ospf_area *area; struct route_node *rn; struct external_info *ei; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; rn = route_node_get (ospf->networks, (struct prefix *)p); if (rn->info) { /* There is already same network statement. */ route_unlock_node (rn); return 0; } rn->info = network = ospf_network_new (area_id, ret); area = ospf_area_get (ospf, area_id, ret); /* Run network config now. */ ospf_network_run ((struct prefix *)p, area); /* Update connected redistribute. */ if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) if (ospf_external_info_find_lsa (ospf, &ei->p)) if (!ospf_distribute_check_connected (ospf, ei)) ospf_external_lsa_flush (ospf, ei->type, &ei->p, ei->ifindex /*, ei->nexthop */); ospf_area_check_free (ospf, area_id); return 1; } int ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, struct in_addr area_id) { struct route_node *rn; struct ospf_network *network; struct external_info *ei; 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)) { int found = 0; struct connected *co = oi->connected; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) { if (rn->info == NULL) continue; if (ospf_network_match_iface(co,&rn->p)) { found = 1; route_unlock_node (rn); break; } } if (found == 0) ospf_if_free (oi); } /* Update connected redistribute. */ if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) if (!ospf_external_info_find_lsa (ospf, &ei->p)) if (ospf_distribute_check_connected (ospf, ei)) ospf_external_lsa_originate (ospf, ei); return 1; } /* 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_network_run_interface (struct prefix *p, struct ospf_area *area, struct interface *ifp) { struct listnode *cnode; struct connected *co; if (memcmp (ifp->name, "VLINK", 5) == 0) return; /* if interface prefix is match specified prefix, then create socket and join multicast group. */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) { if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) continue; if (p->family == co->address->family && ! ospf_if_table_lookup(ifp, co->address) && ospf_network_match_iface(co,p)) { struct ospf_interface *oi; oi = ospf_if_new (area->ospf, ifp, co->address); oi->connected = co; oi->area = area; oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); oi->output_cost = ospf_if_get_output_cost (oi); /* Add pseudo neighbor. */ ospf_nbr_add_self (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 (ifp)->type; 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 (ifp)) ospf_if_up (oi); } } } 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 (p, area, ifp); } 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) { struct route_node *rn; struct ospf_network *network; struct ospf_area *area; if (!ospf) ospf = ospf_lookup (); /* OSPF must be on and Router-ID must be configured. */ if (!ospf || ospf->router_id.s_addr == 0) return; /* Run each netowrk for this interface. */ for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) if (rn->info != NULL) { network = (struct ospf_network *) rn->info; area = ospf_area_get (ospf, network->area_id, network->format); ospf_network_run_interface (&rn->p, area, ifp); } } 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); 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-0.99.22.4/ospfd/ospfd.conf.sample0000644000175000017500000000026612000052240014567 00000000000000! -*- 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-0.99.22.4/ospfd/ospfd.h0000644000175000017500000005213512177450262012640 00000000000000/* * 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 "filter.h" #include "log.h" #define OSPF_VERSION 2 /* Default protocol, port number. */ #ifndef IPPROTO_OSPFIGP #define IPPROTO_OSPFIGP 89 #endif /* IPPROTO_OSPFIGP */ /* IP precedence. */ #ifndef IPTOS_PREC_INTERNETCONTROL #define IPTOS_PREC_INTERNETCONTROL 0xC0 #endif /* IPTOS_PREC_INTERNETCONTROL */ /* VTY port number. */ #define OSPF_VTY_PORT 2604 /* IP TTL for OSPF protocol. */ #define OSPF_IP_TTL 1 #define OSPF_VL_IP_TTL 100 /* Default configuration file name for ospfd. */ #define OSPF_DEFAULT_CONFIG "ospfd.conf" /* Architectual Constants */ #ifdef DEBUG #define OSPF_LS_REFRESH_TIME 60 #else #define OSPF_LS_REFRESH_TIME 1800 #endif #define OSPF_MIN_LS_INTERVAL 5 #define OSPF_MIN_LS_ARRIVAL 1 #define OSPF_LSA_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 0x80000001 #define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffff #define OSPF_NSSA_TRANS_STABLE_DEFAULT 40 #define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ #define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ /* OSPF Authentication Type. */ #define OSPF_AUTH_NULL 0 #define OSPF_AUTH_SIMPLE 1 #define OSPF_AUTH_CRYPTOGRAPHIC 2 /* For Interface authentication setting default */ #define OSPF_AUTH_NOTSET -1 /* For the consumption and sanity of the command handler */ /* DO NIOT REMOVE!!! Need to detect whether a value has been given or not in VLink command handlers */ #define OSPF_AUTH_CMD_NOTSEEN -2 /* OSPF SPF timer values. */ #define OSPF_SPF_DELAY_DEFAULT 200 #define OSPF_SPF_HOLDTIME_DEFAULT 1000 #define OSPF_SPF_MAX_HOLDTIME_DEFAULT 10000 /* 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 /* OSPF options. */ #define OSPF_OPTION_T 0x01 /* TOS. */ #define OSPF_OPTION_E 0x02 #define OSPF_OPTION_MC 0x04 #define OSPF_OPTION_NP 0x08 #define OSPF_OPTION_EA 0x10 #define OSPF_OPTION_DC 0x20 #define OSPF_OPTION_O 0x40 /* OSPF Database Description flags. */ #define OSPF_DD_FLAG_MS 0x01 #define OSPF_DD_FLAG_M 0x02 #define OSPF_DD_FLAG_I 0x04 #define OSPF_DD_FLAG_ALL 0x07 #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) #ifdef HAVE_OPAQUE_LSA /* Opaque-LSA administrative flags. */ u_char opaque; #define OPAQUE_OPERATION_READY_BIT (1 << 0) #define OPAQUE_BLOCK_TYPE_09_LSA_BIT (1 << 1) #define OPAQUE_BLOCK_TYPE_10_LSA_BIT (1 << 2) #define OPAQUE_BLOCK_TYPE_11_LSA_BIT (1 << 3) #endif /* HAVE_OPAQUE_LSA */ /* 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 /* 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. */ #ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ /* Routing tables. */ struct route_table *old_table; /* Old routing table. */ struct route_table *new_table; /* Current routing table. */ struct route_table *old_rtrs; /* Old ABR/ASBR RT. */ struct route_table *new_rtrs; /* New ABR/ASBR RT. */ struct route_table *new_external_route; /* New External Route. */ struct route_table *old_external_route; /* Old External Route. */ struct route_table *external_lsas; /* Database of external LSAs, prefix is LSA's adv. network*/ /* Time stamps. */ struct timeval ts_spf; /* SPF calculation time stamp. */ 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. */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ #endif /* HAVE_OPAQUE_LSA */ #define OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60 unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ #define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30 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]; /* 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; #ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-10 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ /* Area announce list. */ struct { char *name; struct access_list *list; } _export; #define EXPORT_NAME(A) (A)->_export.name #define EXPORT_LIST(A) (A)->_export.list /* Area acceptance list. */ struct { char *name; struct access_list *list; } import; #define IMPORT_NAME(A) (A)->import.name #define IMPORT_LIST(A) (A)->import.list /* Type 3 LSA Area prefix-list. */ struct { char *name; struct prefix_list *list; } plist_in; #define PREFIX_LIST_IN(A) (A)->plist_in.list #define PREFIX_NAME_IN(A) (A)->plist_in.name struct { char *name; struct prefix_list *list; } plist_out; #define PREFIX_LIST_OUT(A) (A)->plist_out.list #define PREFIX_NAME_OUT(A) (A)->plist_out.name /* Shortest Path Tree. */ struct vertex *spf; /* Threads. */ struct thread *t_stub_router; /* Stub-router timer */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ #endif /* HAVE_OPAQUE_LSA */ /* Statistics field. */ u_int32_t spf_calculation; /* SPF Calculation Count. */ /* Router count. */ u_int32_t abr_count; /* ABR router in this area. */ u_int32_t asbr_count; /* ASBR router in this area. */ /* Counters. */ u_int32_t act_ints; /* Active interfaces. */ u_int32_t full_nbrs; /* Fully adjacent neighbors. */ u_int32_t full_vls; /* Fully adjacent virtual neighbors. */ }; /* OSPF config network structure. */ struct ospf_network { /* Area ID. */ struct in_addr area_id; int format; }; /* OSPF NBMA neighbor structure. */ struct ospf_nbr_nbma { /* Neighbor IP address. */ struct in_addr addr; /* OSPF interface. */ struct ospf_interface *oi; /* OSPF neighbor structure. */ struct ospf_neighbor *nbr; /* Neighbor priority. */ u_char priority; /* Poll timer value. */ u_int32_t v_poll; /* Poll timer thread. */ struct thread *t_poll; /* State change. */ u_int32_t state_change; }; /* Macro. */ #define OSPF_AREA_SAME(X,Y) \ (memcmp ((X->area_id), (Y->area_id), IPV4_MAX_BYTELEN) == 0) #define IS_OSPF_ABR(O) ((O)->flags & OSPF_FLAG_ABR) #define IS_OSPF_ASBR(O) ((O)->flags & OSPF_FLAG_ASBR) #define OSPF_IS_AREA_ID_BACKBONE(I) ((I).s_addr == OSPF_AREA_BACKBONE) #define OSPF_IS_AREA_BACKBONE(A) OSPF_IS_AREA_ID_BACKBONE ((A)->area_id) #ifdef roundup # define ROUNDUP(val, gran) roundup(val, gran) #else /* roundup */ # define ROUNDUP(val, gran) (((val) - 1 | (gran) - 1) + 1) #endif /* roundup */ #define LSA_OPTIONS_GET(area) \ (((area)->external_routing == OSPF_AREA_DEFAULT) ? OSPF_OPTION_E : 0) #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_route_map_init (void); extern void ospf_snmp_init (void); extern void ospf_master_init (void); #endif /* _ZEBRA_OSPFD_H */ quagga-0.99.22.4/pkgsrc/0000755000175000017500000000000012211704577011604 500000000000000quagga-0.99.22.4/pkgsrc/Makefile.am0000644000175000017500000000013012000052240013525 00000000000000rcdir=@pkgsrcrcdir@ rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh quagga-0.99.22.4/pkgsrc/Makefile.in0000644000175000017500000003625512211704502013570 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(srcdir)/Makefile.am $(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 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) 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) 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 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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 .PRECIOUS: 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 TAGS: ctags: 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 \ 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 \ uninstall uninstall-am uninstall-rcSCRIPTS # 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-0.99.22.4/pkgsrc/bgpd.sh.in0000644000175000017500000000125312000052240013355 00000000000000#!/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-0.99.22.4/pkgsrc/ospf6d.sh.in0000644000175000017500000000126112000052240013641 00000000000000#!/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-0.99.22.4/pkgsrc/ospfd.sh.in0000644000175000017500000000125612000052240013557 00000000000000#!/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-0.99.22.4/pkgsrc/ripd.sh.in0000644000175000017500000000125312000052240013377 00000000000000#!/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-0.99.22.4/pkgsrc/ripngd.sh.in0000644000175000017500000000126112000052240013723 00000000000000#!/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-0.99.22.4/pkgsrc/zebra.sh.in0000644000175000017500000000162112000052240013543 00000000000000#!/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-0.99.22.4/redhat/0000755000175000017500000000000012211704577011562 500000000000000quagga-0.99.22.4/redhat/Makefile.am0000644000175000017500000000047712177450262013546 00000000000000 EXTRA_DIST = babeld.init babeld.service bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init zebra.init zebra.service quagga-0.99.22.4/redhat/Makefile.in0000644000175000017500000002755612211704502013552 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/quagga.spec.in 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = quagga.spec CONFIG_CLEAN_VPATH_FILES = 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 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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 = babeld.init babeld.service bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init zebra.init zebra.service 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 .PRECIOUS: 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)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags: TAGS TAGS: ctags: 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 \ 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 uninstall uninstall-am # 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-0.99.22.4/redhat/babeld.init0000644000175000017500000000242112177450262013577 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/babeld.conf ### BEGIN INIT INFO # Provides: babeld # Short-Description: Babel routing engine # Description: Babel 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="babeld" cmd=babeld LOCK_FILE=/var/lock/subsys/babeld CONF_FILE=/etc/quagga/babeld.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 $BABELD_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-0.99.22.4/redhat/babeld.service0000644000175000017500000000052212177450262014274 00000000000000[Unit] Description=Babel routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/babeld.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/babeld -d $BABELD_OPTS -f /etc/quagga/babeld.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/bgpd.init0000644000175000017500000000237712177450262013314 00000000000000#!/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-0.99.22.4/redhat/bgpd.service0000644000175000017500000000051012177450262013774 00000000000000[Unit] Description=BGP routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/bgpd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/bgpd -d $BGPD_OPTS -f /etc/quagga/bgpd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/isisd.init0000644000175000017500000000241212177450262013501 00000000000000#!/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-0.99.22.4/redhat/isisd.service0000644000175000017500000000051612177450262014201 00000000000000[Unit] Description=IS-IS routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/isisd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/isisd -d $ISISD_OPTS -f /etc/quagga/isisd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/ospf6d.init0000644000175000017500000000244112177450262013571 00000000000000#!/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-0.99.22.4/redhat/ospf6d.service0000644000175000017500000000053212177450262014265 00000000000000[Unit] Description=OSPF routing daemon for IPv6 BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ospf6d.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ospf6d -d $OSPF6D_OPTS -f /etc/quagga/ospf6d.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/ospfd.init0000644000175000017500000000241012177450262013477 00000000000000#!/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-0.99.22.4/redhat/ospfd.service0000644000175000017500000000051512177450262014200 00000000000000[Unit] Description=OSPF routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ospfd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ospfd -d $OSPFD_OPTS -f /etc/quagga/ospfd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/quagga.logrotate0000644000175000017500000000254112177450262014673 00000000000000/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/babeld.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/babeld.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-0.99.22.4/redhat/quagga.pam0000644000175000017500000000171712000052240013427 00000000000000#%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-0.99.22.4/redhat/quagga.pam.stack0000644000175000017500000000234112000052240014525 00000000000000#%PAM-1.0 # ##### if running quagga as root: # Only allow root (and possibly wheel) to use this because enable access # is unrestricted. auth sufficient /lib/security/$ISA/pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient /lib/security/$ISA/pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. #auth required /lib/security/$ISA/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 /lib/security/$ISA/pam_securetty.so #auth required /lib/security/$ISA/pam_stack.so service=system-auth #auth required /lib/security/$ISA/pam_nologin.so #account required /lib/security/$ISA/pam_stack.so service=system-auth #password required /lib/security/$ISA/pam_stack.so service=system-auth #session required /lib/security/$ISA/pam_stack.so service=system-auth #session optional /lib/security/$ISA/pam_console.so quagga-0.99.22.4/redhat/quagga.spec0000644000175000017500000004206612211704553013625 00000000000000# configure options # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # ####################### Quagga configure options ######################### # with-feature options %{!?with_snmp: %define with_snmp 1 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_ospf_te: %define with_ospf_te 1 } %{!?with_nssa: %define with_nssa 1 } %{!?with_opaque_lsa: %define with_opaque_lsa 1 } %{!?with_tcp_zebra: %define with_tcp_zebra 0 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_pam: %define with_pam 1 } %{!?with_ipv6: %define with_ipv6 1 } %{!?with_ospfclient: %define with_ospfclient 1 } %{!?with_ospfapi: %define with_ospfapi 1 } %{!?with_irdp: %define with_irdp 1 } %{!?with_rtadv: %define with_rtadv 1 } %{!?with_isisd: %define with_isisd 1 } %{!?with_shared: %define with_shared 1 } %{!?with_multipath: %define with_multipath 64 } %{!?quagga_user: %define quagga_user quagga } %{!?vty_group: %define vty_group quaggavty } # path defines %define _sysconfdir /etc/quagga %define zeb_src %{_builddir}/%{name}-%{version} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure %define _libexecdir %{_exec_prefix}/libexec/quagga %define _libdir %{_exec_prefix}/%{_lib}/quagga %define _includedir %{_prefix}/include %define _localstatedir /var/run/quagga ############################################################################ ####################### distro specific tweaks ############################# # default distro. Override with rpmbuild -D "dist XXX" %{expand: %%define default_dist %(rpm -q --qf 'fc%%{VERSION}' fedora-release | grep -v 'not installed')} %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. %define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. %if "%dist" != "fc2" || "%dist" != "fc3" %define quagga_buildreqs %{quagga_buildreqs} texi2html %endif # pam_stack is deprecated in FC5 # default to pam_stack, default should be changed later. %if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack %else %define quagga_pam_source quagga.pam %endif ############################################################################ # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } %{!?quagga_gid: %define quagga_gid 92 } %define daemon_list zebra ripd ospfd bgpd %if %{with_ipv6} %define daemonv6_list ripngd babeld ospf6d %else %define daemonv6_list "" %endif %if %{with_isisd} %define daemon_other isisd %else %define daemon_other "" %endif %define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_other} watchquagga # allow build dir to be kept %{!?keep_build: %define keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %define release_rev 01 } Summary: Routing daemon Name: quagga Version: 0.99.22.4 Release: 20130904%{release_rev} License: GPL Group: System Environment/Daemons Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz URL: http://www.quagga.net %if %{with_snmp} BuildRequires: net-snmp-devel Requires(pre): net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires(pre): ncurses %endif BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 Requires(pre): ncurses pam Requires(pre): /sbin/install-info Provides: routingdaemon BuildRoot: %{_tmppath}/%{name}-%{version}-root Obsoletes: bird gated mrt zebra %description Quagga is a free software that manages TCP/IP based routing protocol. It takes multi-server and multi-thread approach to resolve the current complexity of the Internet. Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. Quagga by design has a process for each protocol. Quagga is a fork of GNU Zebra. %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 %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep %setup -q %build # For standard gcc verbosity, uncomment these lines: #CFLAGS="%{optflags} -Wall -Wsign-compare -Wpointer-arith" #CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" # For ultra gcc verbosity, uncomment these lines also: #CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" #CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" #CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ %if !%{with_shared} --disable-shared \ %endif %if %{with_ipv6} --enable-ipv6 \ %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_nssa} --enable-nssa \ %endif %if %{with_opaque_lsa} --enable-opaque-lsa \ %endif %if %{with_ospf_te} --enable-ospf-te \ %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_pam} --with-libpam \ %endif %if %quagga_user --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif %if %vty_group --enable-vty-group=%vty_group \ %endif --enable-netlink --enable-gcc-rdynamic make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc texi2html -number quagga.texi popd %install rm -rf $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ $RPM_BUILD_ROOT/var/log/quagga $RPM_BUILD_ROOT%{_infodir} make install \ DESTDIR=$RPM_BUILD_ROOT # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf $RPM_BUILD_ROOT/usr/share/info/dir # install etc sources for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} fi done install -m644 %{zeb_rh_src}/%{quagga_pam_source} \ $RPM_BUILD_ROOT/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ $RPM_BUILD_ROOT/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ $RPM_BUILD_ROOT/etc/sysconfig/quagga install -d -m750 $RPM_BUILD_ROOT/var/run/quagga %pre # add vty_group %if %vty_group if getent group %vty_group > /dev/null ; then : ; else \ /usr/sbin/groupadd -r %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if %quagga_user # 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 \ -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" %if %{with_ipv6} zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" %endif zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" zebra_spec_add_service bgpd 2605/tcp "BGPd vty" %if %{with_ipv6} zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" %endif %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 for daemon in %daemon_list ; do /sbin/chkconfig --add ${daemon} done /sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir # 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 %{quagga_user} chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf %endif chmod 640 %{_sysconfdir}/zebra.conf fi if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf 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 running_watchquagga="$restart_watchquagga" restart_watchquagga=no # Stop watchquagga first. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 # 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 # 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 || : fi /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %preun 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 /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir fi %clean %if !%{keep_build} rm -rf $RPM_BUILD_ROOT %endif %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %doc doc/quagga.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if %{quagga_user} %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(755,root,root) /usr/share/info %dir %attr(750,root,root) /var/run/quagga %endif %if %{vty_group} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif %{_infodir}/*info* %{_mandir}/man*/* %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/watchquagga %if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d %{_sbindir}/babeld %endif %if %{with_isisd} %{_sbindir}/isisd %endif %dir %attr(755,root,root) %{_libdir} %if %{with_shared} %dir %{_libdir} %{_libdir}/lib*.so %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %config /etc/rc.d/init.d/* %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %files contrib %defattr(-,root,root) %doc tools %files devel %defattr(-,root,root) %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %{_libdir}/*.a %{_libdir}/*.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 * Thu 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 * Tue Mar 20 2003 Paul Jakma - zebra privileges support * Mon 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-0.99.22.4/redhat/quagga.spec.in0000644000175000017500000004207012177450262014233 00000000000000# configure options # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # ####################### Quagga configure options ######################### # with-feature options %{!?with_snmp: %define with_snmp 1 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_ospf_te: %define with_ospf_te 1 } %{!?with_nssa: %define with_nssa 1 } %{!?with_opaque_lsa: %define with_opaque_lsa 1 } %{!?with_tcp_zebra: %define with_tcp_zebra 0 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_pam: %define with_pam 1 } %{!?with_ipv6: %define with_ipv6 1 } %{!?with_ospfclient: %define with_ospfclient 1 } %{!?with_ospfapi: %define with_ospfapi 1 } %{!?with_irdp: %define with_irdp 1 } %{!?with_rtadv: %define with_rtadv 1 } %{!?with_isisd: %define with_isisd 1 } %{!?with_shared: %define with_shared 1 } %{!?with_multipath: %define with_multipath 64 } %{!?quagga_user: %define quagga_user quagga } %{!?vty_group: %define vty_group quaggavty } # path defines %define _sysconfdir /etc/quagga %define zeb_src %{_builddir}/%{name}-%{version} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure %define _libexecdir %{_exec_prefix}/libexec/quagga %define _libdir %{_exec_prefix}/%{_lib}/quagga %define _includedir %{_prefix}/include %define _localstatedir /var/run/quagga ############################################################################ ####################### distro specific tweaks ############################# # default distro. Override with rpmbuild -D "dist XXX" %{expand: %%define default_dist %(rpm -q --qf 'fc%%{VERSION}' fedora-release | grep -v 'not installed')} %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. %define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. %if "%dist" != "fc2" || "%dist" != "fc3" %define quagga_buildreqs %{quagga_buildreqs} texi2html %endif # pam_stack is deprecated in FC5 # default to pam_stack, default should be changed later. %if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack %else %define quagga_pam_source quagga.pam %endif ############################################################################ # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } %{!?quagga_gid: %define quagga_gid 92 } %define daemon_list zebra ripd ospfd bgpd %if %{with_ipv6} %define daemonv6_list ripngd babeld ospf6d %else %define daemonv6_list "" %endif %if %{with_isisd} %define daemon_other isisd %else %define daemon_other "" %endif %define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_other} watchquagga # allow build dir to be kept %{!?keep_build: %define keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %define release_rev 01 } Summary: Routing daemon Name: quagga Version: @VERSION@ Release: @CONFDATE@%{release_rev} License: GPL Group: System Environment/Daemons Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz URL: http://www.quagga.net %if %{with_snmp} BuildRequires: net-snmp-devel Requires(pre): net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires(pre): ncurses %endif BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 Requires(pre): ncurses pam Requires(pre): /sbin/install-info Provides: routingdaemon BuildRoot: %{_tmppath}/%{name}-%{version}-root Obsoletes: bird gated mrt zebra %description Quagga is a free software that manages TCP/IP based routing protocol. It takes multi-server and multi-thread approach to resolve the current complexity of the Internet. Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. Quagga by design has a process for each protocol. Quagga is a fork of GNU Zebra. %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 %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep %setup -q %build # For standard gcc verbosity, uncomment these lines: #CFLAGS="%{optflags} -Wall -Wsign-compare -Wpointer-arith" #CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" # For ultra gcc verbosity, uncomment these lines also: #CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" #CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" #CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ %if !%{with_shared} --disable-shared \ %endif %if %{with_ipv6} --enable-ipv6 \ %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_nssa} --enable-nssa \ %endif %if %{with_opaque_lsa} --enable-opaque-lsa \ %endif %if %{with_ospf_te} --enable-ospf-te \ %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_pam} --with-libpam \ %endif %if %quagga_user --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif %if %vty_group --enable-vty-group=%vty_group \ %endif --enable-netlink --enable-gcc-rdynamic make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc texi2html -number quagga.texi popd %install rm -rf $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ $RPM_BUILD_ROOT/var/log/quagga $RPM_BUILD_ROOT%{_infodir} make install \ DESTDIR=$RPM_BUILD_ROOT # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf $RPM_BUILD_ROOT/usr/share/info/dir # install etc sources for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} fi done install -m644 %{zeb_rh_src}/%{quagga_pam_source} \ $RPM_BUILD_ROOT/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ $RPM_BUILD_ROOT/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ $RPM_BUILD_ROOT/etc/sysconfig/quagga install -d -m750 $RPM_BUILD_ROOT/var/run/quagga %pre # add vty_group %if %vty_group if getent group %vty_group > /dev/null ; then : ; else \ /usr/sbin/groupadd -r %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if %quagga_user # 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 \ -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" %if %{with_ipv6} zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" %endif zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" zebra_spec_add_service bgpd 2605/tcp "BGPd vty" %if %{with_ipv6} zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" %endif %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 for daemon in %daemon_list ; do /sbin/chkconfig --add ${daemon} done /sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir # 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 %{quagga_user} chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf %endif chmod 640 %{_sysconfdir}/zebra.conf fi if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf 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 running_watchquagga="$restart_watchquagga" restart_watchquagga=no # Stop watchquagga first. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 # 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 # 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 || : fi /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %preun 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 /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir fi %clean %if !%{keep_build} rm -rf $RPM_BUILD_ROOT %endif %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %doc doc/quagga.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if %{quagga_user} %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(755,root,root) /usr/share/info %dir %attr(750,root,root) /var/run/quagga %endif %if %{vty_group} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif %{_infodir}/*info* %{_mandir}/man*/* %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/watchquagga %if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d %{_sbindir}/babeld %endif %if %{with_isisd} %{_sbindir}/isisd %endif %dir %attr(755,root,root) %{_libdir} %if %{with_shared} %dir %{_libdir} %{_libdir}/lib*.so %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %config /etc/rc.d/init.d/* %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %files contrib %defattr(-,root,root) %doc tools %files devel %defattr(-,root,root) %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %{_libdir}/*.a %{_libdir}/*.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 * Thu 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 * Tue Mar 20 2003 Paul Jakma - zebra privileges support * Mon 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-0.99.22.4/redhat/quagga.sysconfig0000644000175000017500000000152112177450262014674 00000000000000# # 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" # 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-0.99.22.4/redhat/ripd.init0000644000175000017500000000237712177450262013336 00000000000000#!/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-0.99.22.4/redhat/ripd.service0000644000175000017500000000051012177450262014016 00000000000000[Unit] Description=RIP routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ripd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ripd -d $RIPD_OPTS -f /etc/quagga/ripd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/ripngd.init0000644000175000017500000000243712177450262013660 00000000000000#!/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-0.99.22.4/redhat/ripngd.service0000644000175000017500000000053112177450262014346 00000000000000[Unit] Description=RIP routing daemon for IPv6 BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ripngd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ripngd -d $RIPNGD_OPTS -f /etc/quagga/ripngd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/redhat/watchquagga.init0000644000175000017500000000223112177450262014661 00000000000000#!/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-0.99.22.4/redhat/zebra.init0000644000175000017500000000244312177450262013475 00000000000000#!/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-0.99.22.4/redhat/zebra.service0000644000175000017500000000053712177450262014174 00000000000000[Unit] Description=GNU Zebra routing manager After=syslog.target network.target ConditionPathExists=/etc/quagga/zebra.conf [Service] Type=forking EnvironmentFile=-/etc/sysconfig/quagga ExecStartPre=/sbin/ip route flush proto zebra ExecStart=/usr/sbin/zebra -d $ZEBRA_OPTS -f /etc/quagga/zebra.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.22.4/ripd/0000755000175000017500000000000012211704577011251 500000000000000quagga-0.99.22.4/ripd/Makefile.am0000644000175000017500000000126212177450262013226 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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-0.99.22.4/ripd/Makefile.in0000644000175000017500000005440612211704502013233 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru 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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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 .PRECIOUS: 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) -rm -f librip.a $(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD) $(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) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/ripd/RIPv2-MIB.txt0000644000175000017500000004051312000052240013217 00000000000000 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-0.99.22.4/ripd/rip_debug.c0000644000175000017500000001571612051607643013305 00000000000000/* 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-0.99.22.4/ripd/rip_debug.h0000644000175000017500000000332712051607643013305 00000000000000/* 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-0.99.22.4/ripd/rip_interface.c0000644000175000017500000014503712132522417014152 00000000000000/* 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); 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, unsigned int 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, unsigned int 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; } /* 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)); /* 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; 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) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist. */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; rip_if_down(ifp); if (IS_RIP_DEBUG_ZEBRA) zlog_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) { struct interface *ifp; /* zebra_interface_state_read () updates interface structure in iflist. */ ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; if (IS_RIP_DEBUG_ZEBRA) zlog_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) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); 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) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; if (if_is_up (ifp)) { rip_if_down(ifp); } zlog_info("interface delete %s index %d flags %#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; } void rip_interface_clean (void) { struct listnode *node; struct interface *ifp; struct rip_interface *ri; for (ALL_LIST_ELEMENTS_RO (iflist, node, 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 rip_interface_reset (void) { struct listnode *node; struct interface *ifp; struct rip_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->ri_send = RI_RIP_UNSPEC; ri->ri_receive = RI_RIP_UNSPEC; ri->auth_type = RIP_NO_AUTH; if (ri->auth_str) { free (ri->auth_str); ri->auth_str = NULL; } if (ri->key_chain) { free (ri->key_chain); ri->key_chain = NULL; } ri->split_horizon = RIP_NO_SPLIT_HORIZON; ri->split_horizon_default = RIP_NO_SPLIT_HORIZON; ri->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; ri->prefix[RIP_FILTER_IN] = NULL; ri->prefix[RIP_FILTER_OUT] = NULL; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup); ri->t_wakeup = NULL; } ri->recv_badpackets = 0; ri->recv_badroutes = 0; ri->sent_updates = 0; ri->passive = 0; } } int rip_if_down(struct interface *ifp) { struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri = NULL; if (rip) { for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { /* Routes got through this interface. */ if (rinfo->ifindex == ifp->ifindex && rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE) { rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &rp->p, &rinfo->nexthop, rinfo->metric); rip_redistribute_delete (rinfo->type,rinfo->sub_type, (struct prefix_ipv4 *)&rp->p, rinfo->ifindex); } else { /* All redistributed routes but static and system */ if ((rinfo->ifindex == ifp->ifindex) && /* (rinfo->type != ZEBRA_ROUTE_STATIC) && */ (rinfo->type != ZEBRA_ROUTE_SYSTEM)) rip_redistribute_delete (rinfo->type,rinfo->sub_type, (struct prefix_ipv4 *)&rp->p, rinfo->ifindex); } } } ri = ifp->info; if (ri->running) { if (IS_RIP_DEBUG_EVENT) zlog_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); } int rip_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); 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) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); 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); } 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); } } } /* 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_init(); if_add_hook (IF_NEW_HOOK, rip_interface_new_hook); if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook); /* RIP network init. */ rip_enable_interface = vector_init (1); rip_enable_network = route_table_init (); /* RIP passive interface. */ Vrip_passive_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-0.99.22.4/ripd/rip_interface.h0000644000175000017500000000244412051607643014156 00000000000000/* 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); extern int rip_interface_up (int , struct zclient *, zebra_size_t); extern int rip_interface_add (int , struct zclient *, zebra_size_t); extern int rip_interface_delete (int , struct zclient *, zebra_size_t); extern int rip_interface_address_add (int , struct zclient *, zebra_size_t); extern int rip_interface_address_delete (int , struct zclient *, zebra_size_t); #endif /* _QUAGGA_RIP_INTERFACE_H */ quagga-0.99.22.4/ripd/rip_main.c0000644000175000017500000001603212177450262013135 00000000000000/* 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 "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; struct thread thread; /* Set umask before anything for security */ umask (0027); /* Get program name. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); /* First of all we need logging init. */ zlog_default = openzlog (progname, ZLOG_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 (); /* RIP related initialization. */ rip_init (); rip_if_init (); rip_zclient_init (); rip_peer_init (); /* Sort all installed commands. */ sort_node (); /* Get configuration file. */ vty_read_config (config_file, config_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. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return (0); } quagga-0.99.22.4/ripd/rip_offset.c0000644000175000017500000002524612051607643013504 00000000000000/* 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-0.99.22.4/ripd/rip_peer.c0000644000175000017500000001114512051607643013142 00000000000000/* 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-0.99.22.4/ripd/rip_routemap.c0000644000175000017500000006752312051607643014056 00000000000000/* 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, "%% 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; } /* 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, "%% 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; } /* 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, "%% 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, "%% 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, "%% 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; } /* 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) { u_short *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 `match tag' match statement. `arg' is TAG value */ static void * route_match_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `match tag' value. */ static void route_match_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag matching. */ struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_match_tag_compile, route_match_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) { u_short *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 `tag' compile function. Given string is converted to u_short. */ static void * route_set_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_set_tag_compile, route_set_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 <0-65535>", 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 <0-65535>", 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>|<+/-metric>)", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\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 <0-65535>", 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 <0-65535>", 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, &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-0.99.22.4/ripd/rip_snmp.c0000644000175000017500000003513112177450262013167 00000000000000/* 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 == name[v->namelen + sizeof (struct in_addr)]) return peer; return NULL; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); len = *length - v->namelen; peer = rip_peer_lookup (addr); if (peer) { if ((len < sizeof (struct in_addr) + 1) || (peer->domain > name[v->namelen + sizeof (struct in_addr)])) { oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); name[v->namelen + sizeof (struct in_addr)] = peer->domain; *length = sizeof (struct in_addr) + v->namelen + 1; return peer; } } peer = rip_peer_lookup_next (addr); if (! peer) return NULL; oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); name[v->namelen + sizeof (struct in_addr)] = peer->domain; *length = sizeof (struct in_addr) + v->namelen + 1; return peer; } return NULL; } static u_char * rip2IfStatEntry (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct interface *ifp; struct rip_interface *ri; static struct in_addr addr; static long valid = SNMP_VALID; 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-0.99.22.4/ripd/rip_zebra.c0000644000175000017500000004243112177450262013316 00000000000000/* RIPd and zebra interface. * Copyright (C) 1997, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "stream.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" /* All information about zebra. */ struct zclient *zclient = NULL; /* RIPd to zebra command interface. */ void rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, u_int32_t metric, u_char distance) { struct zapi_ipv4 api; if (zclient->redist[ZEBRA_ROUTE_RIP]) { api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api); rip_global_route_changes++; } } void rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, u_int32_t metric) { struct zapi_ipv4 api; if (zclient->redist[ZEBRA_ROUTE_RIP]) { api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); rip_global_route_changes++; } } /* Zebra route add and delete treatment. */ static int rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop.s_addr = stream_get_ipv4 (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 255; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 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); 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 (zclient->redist[type]) return CMD_SUCCESS; zclient->redist[type] = 1; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } #endif static int rip_redistribute_unset (int type) { if (! zclient->redist[type]) return CMD_SUCCESS; zclient->redist[type] = 0; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); /* Remove the routes from RIP table. */ rip_redistribute_withdraw (type); return CMD_SUCCESS; } int rip_redistribute_check (int type) { return (zclient->redist[type]); } void rip_redistribute_clean (void) { int i; for (i = 0; redist_type[i].str; i++) { if (zclient->redist[redist_type[i].type]) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, redist_type[i].type); zclient->redist[redist_type[i].type] = 0; /* Remove the routes from RIP table. */ rip_redistribute_withdraw (redist_type[i].type); } } } DEFUN (rip_redistribute_rip, rip_redistribute_rip_cmd, "redistribute rip", "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") { zclient->redist[ZEBRA_ROUTE_RIP] = 1; return CMD_SUCCESS; } DEFUN (no_rip_redistribute_rip, no_rip_redistribute_rip_cmd, "no redistribute rip", NO_STR "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") { zclient->redist[ZEBRA_ROUTE_RIP] = 0; return CMD_SUCCESS; } DEFUN (rip_redistribute_type, rip_redistribute_type_cmd, "redistribute " 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); 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); 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); 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); 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); } 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 (! zclient->redist[ZEBRA_ROUTE_RIP]) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute rip%s", VTY_NEWLINE); return 1; } return 0; } int config_write_rip_redistribute (struct vty *vty, int config_mode) { int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) { if (config_mode) { if (rip->route_map[i].metric_config) { if (rip->route_map[i].name) vty_out (vty, " redistribute %s metric %d route-map %s%s", 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)# ", }; void rip_zclient_init () { /* Set default value to the zebra client structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_RIP); zclient->interface_add = rip_interface_add; zclient->interface_delete = rip_interface_delete; zclient->interface_address_add = rip_interface_address_add; zclient->interface_address_delete = rip_interface_address_delete; zclient->ipv4_route_add = rip_zebra_read_ipv4; zclient->ipv4_route_delete = rip_zebra_read_ipv4; zclient->interface_up = rip_interface_up; zclient->interface_down = rip_interface_down; /* Install zebra node. */ install_node (&zebra_node, config_write_zebra); /* Install command elements to zebra node. */ install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); install_default (ZEBRA_NODE); install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd); install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd); /* Install command elements to rip node. */ install_element (RIP_NODE, &rip_redistribute_type_cmd); install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd); install_element (RIP_NODE, &rip_redistribute_type_metric_cmd); install_element (RIP_NODE, &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-0.99.22.4/ripd/ripd.c0000644000175000017500000033255512177450262012310 00000000000000/* 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. */ rp->info = NULL; route_unlock_node (rp); /* Free RIP routing information. */ rip_info_free (rinfo); return 0; } /* Timeout RIP routes. */ static int rip_timeout (struct thread *t) { struct rip_info *rinfo; struct route_node *rn; rinfo = THREAD_ARG (t); rinfo->t_timeout = NULL; rn = rinfo->rp; /* - The garbage-collection timer is set for 120 seconds. */ RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop, rinfo->metric); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service. */ rinfo->metric = RIP_METRIC_INFINITY; rinfo->flags &= ~RIP_RTF_FIB; /* - The route change flag is to indicate that this entry has been changed. */ rinfo->flags |= RIP_RTF_CHANGED; /* - The output process is signalled to trigger a response. */ rip_event (RIP_TRIGGERED_UPDATE, 0); return 0; } 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_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; /* Input distribute-list filtering. */ if (ri->list[RIP_FILTER_IN]) { if (access_list_apply (ri->list[RIP_FILTER_IN], (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIP_FILTER_IN]) { if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } static int rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; if (ri->list[RIP_FILTER_OUT]) { if (access_list_apply (ri->list[RIP_FILTER_OUT], (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by distribute out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIP_FILTER_OUT]) { if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by prefix-list out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } /* Check nexthop address validity. */ static int rip_nexthop_check (struct in_addr *addr) { 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, rinfotmp; struct rip_interface *ri; struct in_addr *nexthop; u_char oldmetric; int same = 0; int route_reuse = 0; unsigned char old_dist, new_dist; /* Make prefix structure. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefix = rte->prefix; p.prefixlen = ip_masklen (rte->mask); /* Make sure mask is applied. */ apply_mask_ipv4 (&p); /* Apply input filters. */ ri = ifp->info; ret = rip_incoming_filter (&p, ri); if (ret < 0) return; /* Modify entry according to the interface routemap. */ if (ri->routemap[RIP_FILTER_IN]) { int ret; struct rip_info newinfo; 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 */ /* 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; 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); /* Check to see whether there is already RIP route on the table. */ rinfo = rp->info; 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) { /* Fill in a minimaly temporary rip_info structure, for a future rip_distance_apply() use) */ memset (&rinfotmp, 0, sizeof (rinfotmp)); IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr); rinfotmp.rp = rinfo->rp; new_dist = rip_distance_apply (&rinfotmp); new_dist = new_dist ? new_dist : ZEBRA_RIP_DISTANCE_DEFAULT; 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) { route_unlock_node (rp); return; } else { RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); rp->info = NULL; if (rip_route_rte (rinfo)) rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, rinfo->metric); rip_info_free (rinfo); rinfo = NULL; route_reuse = 1; } } } if (!rinfo) { /* Now, check to see whether there is already an explicit route for the destination prefix. If there is no such route, add this route to the routing table, unless the metric is infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIP_METRIC_INFINITY) { rinfo = rip_info_new (); /* - Setting the destination prefix and length to those in the RTE. */ rinfo->rp = rp; /* - Setting the metric to the newly calculated metric (as described above). */ rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); /* - Set the next hop address to be the address of the router from which the datagram came or the next hop address specified by a next hop RTE. */ IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); rinfo->ifindex = ifp->ifindex; /* - Initialize the timeout for the route. If the garbage-collection timer is running for this route, stop it (see section 2.3 for a discussion of the timers). */ rip_timeout_update (rinfo); /* - Set the route change flag. */ rinfo->flags |= RIP_RTF_CHANGED; /* - Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); /* Finally, route goes into the kernel. */ rinfo->type = ZEBRA_ROUTE_RIP; rinfo->sub_type = RIP_ROUTE_RTE; /* Set distance value. */ rinfo->distance = rip_distance_apply (rinfo); rp->info = rinfo; rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric, rinfo->distance); rinfo->flags |= RIP_RTF_FIB; } /* Unlock temporary lock, i.e. same behaviour */ if (route_reuse) route_unlock_node (rp); } else { /* Route is there but we are not sure the route is RIP or not. */ rinfo = rp->info; /* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. If this datagram is from the same router as the existing route, reinitialize the timeout. */ same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && (rinfo->ifindex == ifp->ifindex)); if (same) rip_timeout_update (rinfo); /* Fill in a minimaly temporary rip_info structure, for a future rip_distance_apply() use) */ memset (&rinfotmp, 0, sizeof (rinfotmp)); IPV4_ADDR_COPY (&rinfotmp.from, &from->sin_addr); rinfotmp.rp = rinfo->rp; /* 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) && ntohs (rte->tag) != rinfo->tag) || (rinfo->distance > rip_distance_apply (&rinfotmp)) || ((rinfo->distance != rip_distance_apply (rinfo)) && same)) { /* - Adopt the route from the datagram. That is, put the new metric in, and adjust the next hop address (if necessary). */ oldmetric = rinfo->metric; rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr); rinfo->ifindex = ifp->ifindex; rinfo->distance = rip_distance_apply (rinfo); /* Should a new route to this network be established while the garbage-collection timer is running, the new route will replace the one that is about to be deleted. In this case the garbage-collection timer must be cleared. */ if (oldmetric == RIP_METRIC_INFINITY && rinfo->metric < RIP_METRIC_INFINITY) { rinfo->type = ZEBRA_ROUTE_RIP; rinfo->sub_type = RIP_ROUTE_RTE; RIP_TIMER_OFF (rinfo->t_garbage_collect); if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, rinfo->distance); rinfo->flags |= RIP_RTF_FIB; } /* Update nexthop and/or metric value. */ if (oldmetric != RIP_METRIC_INFINITY) { rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); rip_zebra_ipv4_add (&p, nexthop, rinfo->metric, rinfo->distance); rinfo->flags |= RIP_RTF_FIB; if (!IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV4_ADDR_COPY (&rinfo->nexthop, nexthop); } /* - Set the route change flag and signal the output process to trigger an update. */ rinfo->flags |= RIP_RTF_CHANGED; rip_event (RIP_TRIGGERED_UPDATE, 0); /* - If the new metric is infinity, start the deletion process (described above); */ if (rinfo->metric == RIP_METRIC_INFINITY) { /* If the new metric is infinity, the deletion process begins for the route, which is no longer used for routing packets. Note that the deletion process is started only when the metric is first set to infinity. If the metric was already infinity, then a new deletion process is not started. */ if (oldmetric != RIP_METRIC_INFINITY) { /* - The garbage-collection timer is set for 120 seconds. */ RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service. */ rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric); rinfo->flags &= ~RIP_RTF_FIB; /* - The route change flag is to indicate that this entry has been changed. */ /* - The output process is signalled to trigger a response. */ ; /* Above processes are already done previously. */ } } else { /* otherwise, re-initialize the timeout. */ rip_timeout_update (rinfo); } } /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } } /* Dump RIP packet */ 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", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } else { zlog_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; /* 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's netmask is ignored. */ if (packet->version == RIPv2 && (rte->prefix.s_addr == 0) && (rte->mask.s_addr != 0)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("Default route with non-zero netmask. Set zero to netmask"); rte->mask.s_addr = 0; } /* 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, unsigned int ifindex, struct in_addr *nexthop, unsigned int metric, unsigned char distance) { int ret; struct route_node *rp; struct rip_info *rinfo; /* Redistribute route */ ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_get (rip->table, (struct prefix *) p); rinfo = rp->info; if (rinfo) { if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIP_ROUTE_INTERFACE && rinfo->metric != RIP_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Manually configured RIP route check. */ if (rinfo->type == ZEBRA_ROUTE_RIP && ((rinfo->sub_type == RIP_ROUTE_STATIC) || (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; } } RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); if (rip_route_rte (rinfo)) rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, rinfo->metric); rp->info = NULL; rip_info_free (rinfo); route_unlock_node (rp); } rinfo = rip_info_new (); rinfo->type = type; rinfo->sub_type = sub_type; rinfo->ifindex = ifindex; rinfo->metric = 1; rinfo->external_metric = metric; rinfo->distance = distance; rinfo->rp = rp; if (nexthop) rinfo->nexthop = *nexthop; rinfo->flags |= RIP_RTF_FIB; rp->info = rinfo; rinfo->flags |= RIP_RTF_CHANGED; 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, unsigned int ifindex) { int ret; struct route_node *rp; struct rip_info *rinfo; ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_lookup (rip->table, (struct prefix *) p); if (rp) { rinfo = rp->info; if (rinfo != NULL && rinfo->type == type && rinfo->sub_type == sub_type && rinfo->ifindex == ifindex) { /* Perform poisoned reverse. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; 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); } } } /* 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) { struct prefix_ipv4 saddr; /* saddr will be used for determining which routes to split-horizon. Since the source address we'll pick will be on the same subnet as the destination, for the purpose of split-horizoning, we'll pretend that "from" is our source address. */ saddr.family = AF_INET; saddr.prefixlen = IPV4_MAX_BITLEN; saddr.prefix = from->sin_addr; /* 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 = 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, int *ifindex) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *ptr; char adata[1024]; msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = size; ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (ptr = 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; unsigned int ifindex; /* Fetch socket then register myself. */ sock = THREAD_FD (t); rip_event (RIP_READ, sock); /* Read RIP packet. */ ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex); if (ret < 0) { zlog_warn ("Can't read RIP packet: %s", 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; /* 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_PACKET_MAXSIZ - 4) / 20; /* 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 ((rinfo = rp->info) != NULL) { /* 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_outgoing_filter (p, ri); if (ret < 0) continue; /* Changed route only output. */ if (route_type == rip_changed_route && (! (rinfo->flags & RIP_RTF_CHANGED))) continue; /* Split horizon. */ /* if (split_horizon == rip_split_horizon) */ if (ri->split_horizon == 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). */ if (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->ifindex == ifc->ifp->ifindex) continue; if (rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) 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). */ if (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->ifindex == ifc->ifp->ifindex) rinfo->metric_out = RIP_METRIC_INFINITY; if (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->name : "_unknown_"), 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) && if_is_multicast(ifp)) 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 doesnt have connected interface!", inet_ntoa (p->prefix)); continue; } if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL) { zlog_warn ("Neighbor %s doesnt 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; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) if (rinfo->flags & RIP_RTF_CHANGED) rinfo->flags &= ~RIP_RTF_CHANGED; } /* Triggered update interval timer. */ 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; if (!rip) return; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { if (rinfo->type == type && rinfo->sub_type != RIP_ROUTE_INTERFACE) { /* Perform poisoned reverse. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; 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 = (((rand () % ((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); 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; for (np = route_top (rip->table); np; np = route_next (np)) if ((rinfo = np->info) != NULL) if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) rinfo->metric = rip->default_metric; } #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; u_char distance; struct route_node *rn; struct rip_distance *rdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); if (! rn) { vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); return CMD_WARNING; } rdistance = rn->info; if (rdistance->access_list) free (rdistance->access_list); rip_distance_free (rdistance); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); return CMD_SUCCESS; } 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; } /* 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; 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 ((rinfo = np->info) != NULL) { 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); /* 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_IN]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); if (alist) ri->list[RIP_FILTER_IN] = alist; else ri->list[RIP_FILTER_IN] = NULL; } else ri->list[RIP_FILTER_IN] = NULL; if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); if (alist) ri->list[RIP_FILTER_OUT] = alist; else ri->list[RIP_FILTER_OUT] = NULL; } else ri->list[RIP_FILTER_OUT] = NULL; if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); if (plist) ri->prefix[RIP_FILTER_IN] = plist; else ri->prefix[RIP_FILTER_IN] = NULL; } else ri->prefix[RIP_FILTER_IN] = NULL; if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); if (plist) ri->prefix[RIP_FILTER_OUT] = plist; else ri->prefix[RIP_FILTER_OUT] = NULL; } else ri->prefix[RIP_FILTER_OUT] = NULL; } void rip_distribute_update_interface (struct interface *ifp) { struct distribute *dist; dist = distribute_lookup (ifp->name); if (dist) rip_distribute_update (dist); } /* Update all interface's distribute list. */ /* 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(struct access_list *notused) { rip_distribute_update_all(NULL); } /* Delete all added rip route. */ void rip_clean (void) { int i; struct route_node *rp; struct rip_info *rinfo; if (rip) { /* Clear RIP routes */ for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { if (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE) rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop, rinfo->metric); RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); rp->info = NULL; route_unlock_node (rp); rip_info_free (rinfo); } /* Cancel RIP related timers. */ RIP_TIMER_OFF (rip->t_update); RIP_TIMER_OFF (rip->t_triggered_update); RIP_TIMER_OFF (rip->t_triggered_interval); /* Cancel read thread. */ if (rip->t_read) { thread_cancel (rip->t_read); rip->t_read = NULL; } /* Close RIP socket. */ if (rip->sock >= 0) { close (rip->sock); rip->sock = -1; } /* Static RIP route configuration. */ for (rp = route_top (rip->route); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } /* RIP neighbor configuration. */ for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } /* Redistribute related clear. */ if (rip->default_information_route_map) free (rip->default_information_route_map); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (rip->route_map[i].name) free (rip->route_map[i].name); XFREE (MTYPE_ROUTE_TABLE, rip->table); XFREE (MTYPE_ROUTE_TABLE, rip->route); XFREE (MTYPE_ROUTE_TABLE, rip->neighbor); XFREE (MTYPE_RIP, rip); rip = NULL; } rip_clean_network (); rip_passive_nondefault_clean (); rip_offset_clean (); rip_interface_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_interface_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(). */ srand (time (NULL)); /* Install top nodes. */ install_node (&rip_node, config_write_rip); /* Install rip commands. */ install_element (VIEW_NODE, &show_ip_rip_cmd); install_element (VIEW_NODE, &show_ip_rip_status_cmd); install_element (ENABLE_NODE, &show_ip_rip_cmd); install_element (ENABLE_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); /* 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-0.99.22.4/ripd/ripd.conf.sample0000644000175000017500000000062612000052240014235 00000000000000! -*- 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-0.99.22.4/ripd/ripd.h0000644000175000017500000002702612132522417012300 00000000000000/* 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 25 /* RIP version 2 multicast address. */ #ifndef INADDR_RIP_GROUP #define INADDR_RIP_GROUP 0xe0000009 /* 224.0.0.9 */ #endif /* RIP timers */ #define RIP_UPDATE_TIMER_DEFAULT 30 #define RIP_TIMEOUT_TIMER_DEFAULT 180 #define RIP_GARBAGE_TIMER_DEFAULT 120 /* RIP peer timeout value. */ #define RIP_PEER_TIMER_DEFAULT 180 /* RIP port number. */ #define RIP_PORT_DEFAULT 520 #define RIP_VTY_PORT 2602 /* 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; /* For redistribute route map. */ struct { char *name; struct route_map *map; int metric_config; u_int32_t metric; } route_map[ZEBRA_ROUTE_MAX]; }; /* RIP routing table entry which belong to rip_packet. */ struct rte { u_int16_t family; /* Address family of this route. */ u_int16_t tag; /* Route Tag which included in RIP2 packet. */ struct in_addr prefix; /* Prefix of rip route. */ struct in_addr mask; /* Netmask of rip route. */ struct in_addr nexthop; /* Next hop of rip route. */ u_int32_t metric; /* Metric value of rip route. */ }; /* RIP packet structure. */ struct rip_packet { unsigned char command; /* Command type of RIP packet. */ unsigned char version; /* RIP version which coming from peer. */ unsigned char pad1; /* Padding of RIP packet header. */ unsigned char pad2; /* Same as above. */ struct rte rte[1]; /* Address structure. */ }; /* Buffer to read RIP packet. */ union rip_buf { struct rip_packet rip_packet; char buf[RIP_PACKET_MAXSIZ]; }; /* RIP route information. */ struct rip_info { /* This route's type. */ int type; /* Sub type. */ int sub_type; /* RIP nexthop. */ struct in_addr nexthop; struct in_addr from; /* Which interface does this route come from. */ unsigned int ifindex; /* Metric of this route. */ u_int32_t metric; /* 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_short tag_out; unsigned int ifindex_out; struct route_node *rp; u_char distance; #ifdef NEW_RIP_TABLE struct rip_info *next; struct rip_info *prev; #endif /* NEW_RIP_TABLE */ }; 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_interface_clean (void); extern void rip_interface_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 (void); 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 *, unsigned int, struct in_addr *, unsigned int, unsigned char); extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); extern void rip_redistribute_withdraw (int); extern void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char); extern void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t); 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 *); /* 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-0.99.22.4/ripngd/0000755000175000017500000000000012211704577011576 500000000000000quagga-0.99.22.4/ripngd/Makefile.am0000644000175000017500000000133112177450262013550 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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-0.99.22.4/ripngd/Makefile.in0000644000175000017500000005506012211704502013555 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru 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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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 .PRECIOUS: 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) -rm -f libripng.a $(libripng_a_AR) libripng.a $(libripng_a_OBJECTS) $(libripng_a_LIBADD) $(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) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/ripngd/ripng_debug.c0000644000175000017500000001726112045513244014150 00000000000000/* * 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, &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-0.99.22.4/ripngd/ripng_debug.h0000644000175000017500000000325012045513244014146 00000000000000/* * 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-0.99.22.4/ripngd/ripng_interface.c0000644000175000017500000007252112132522417015021 00000000000000/* * 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 "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; if (ripng) { for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { /* Routes got through this interface. */ if (rinfo->ifindex == ifp->ifindex && rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE) { ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, &rinfo->nexthop, rinfo->ifindex); ripng_redistribute_delete (rinfo->type, rinfo->sub_type, (struct prefix_ipv6 *)&rp->p, rinfo->ifindex); } else { /* All redistributed routes got through this interface, * but the static and system ones are kept. */ if ((rinfo->ifindex == ifp->ifindex) && (rinfo->type != ZEBRA_ROUTE_STATIC) && (rinfo->type != ZEBRA_ROUTE_SYSTEM)) ripng_redistribute_delete (rinfo->type, rinfo->sub_type, (struct prefix_ipv6 *) &rp->p, rinfo->ifindex); } } } 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) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (ifp == NULL) return 0; if (IS_RIPNG_DEBUG_ZEBRA) zlog_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) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (ifp == NULL) return 0; ripng_if_down (ifp); if (IS_RIPNG_DEBUG_ZEBRA) zlog_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) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); 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) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; if (if_is_up (ifp)) { 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); } int ripng_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; struct prefix *p; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); 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) { struct connected *ifc; struct prefix *p; char buf[INET6_ADDRSTRLEN]; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); 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); } 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); } } } /* 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. */ iflist = list_new (); 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-0.99.22.4/ripngd/ripng_main.c0000644000175000017500000001557212177450262014017 00000000000000/* * 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 "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; struct thread thread; 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 (); /* RIPngd inits. */ ripng_init (); zebra_init (); ripng_peer_init (); /* Sort all installed commands. */ sort_node (); /* 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. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return 0; } quagga-0.99.22.4/ripngd/ripng_nexthop.c0000644000175000017500000001336612000052240014532 00000000000000/* 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"); num = 0; stream_reset (s); } } quagga-0.99.22.4/ripngd/ripng_nexthop.h0000644000175000017500000000432212000052240014527 00000000000000/* 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) { #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*/ #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-0.99.22.4/ripngd/ripng_offset.c0000644000175000017500000002601712000052240014330 00000000000000/* 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-0.99.22.4/ripngd/ripng_peer.c0000644000175000017500000001161312000052240013771 00000000000000/* 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-0.99.22.4/ripngd/ripng_route.c0000644000175000017500000000716312000052240014201 00000000000000/* * 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; } static void ripng_aggregate_free (struct ripng_aggregate *aggregate) { XFREE (MTYPE_RIPNG_AGGREGATE, aggregate); } /* Aggregate count increment check. */ void ripng_aggregate_increment (struct route_node *child, struct ripng_info *rinfo) { struct route_node *np; struct ripng_aggregate *aggregate; for (np = child; np; np = np->parent) if ((aggregate = np->aggregate) != NULL) { aggregate->count++; rinfo->suppress++; } } /* Aggregate count decrement check. */ void ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo) { struct route_node *np; struct ripng_aggregate *aggregate; for (np = child; np; np = np->parent) if ((aggregate = np->aggregate) != NULL) { aggregate->count--; rinfo->suppress--; } } /* RIPng routes treatment. */ int ripng_aggregate_add (struct prefix *p) { struct route_node *top; struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct ripng_aggregate *sub; /* Get top node for aggregation. */ top = route_node_get (ripng->table, p); /* Allocate new aggregate. */ aggregate = ripng_aggregate_new (); aggregate->metric = 1; top->aggregate = aggregate; /* Suppress routes match to the aggregate. */ for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) { /* Suppress normal route. */ if ((rinfo = rp->info) != NULL) { aggregate->count++; rinfo->suppress++; } /* Suppress aggregate route. This may not need. */ if (rp != top && (sub = rp->aggregate) != NULL) { aggregate->count++; sub->suppress++; } } return 0; } /* Delete RIPng static route. */ int ripng_aggregate_delete (struct prefix *p) { struct route_node *top; struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct ripng_aggregate *sub; /* Get top node for aggregation. */ top = route_node_get (ripng->table, p); /* Allocate new aggregate. */ aggregate = top->aggregate; /* Suppress routes match to the aggregate. */ for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) { /* Suppress normal route. */ if ((rinfo = rp->info) != NULL) { aggregate->count--; rinfo->suppress--; } if (rp != top && (sub = rp->aggregate) != NULL) { aggregate->count--; sub->suppress--; } } top->aggregate = NULL; ripng_aggregate_free (aggregate); route_unlock_node (top); route_unlock_node (top); return 0; } quagga-0.99.22.4/ripngd/ripng_route.h0000644000175000017500000000321112000052240014174 00000000000000/* * RIPng daemon * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIPNG_ROUTE_H #define _ZEBRA_RIPNG_ROUTE_H struct ripng_aggregate { /* Aggregate route count. */ unsigned int count; /* Suppressed route count. */ unsigned int suppress; /* Metric of this route. */ u_char metric; /* Tag field of RIPng packet.*/ u_short tag; /* Route-map futures - this variables can be changed. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; u_short 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 int ripng_aggregate_add (struct prefix *p); extern int ripng_aggregate_delete (struct prefix *p); #endif /* _ZEBRA_RIPNG_ROUTE_H */ quagga-0.99.22.4/ripngd/ripng_routemap.c0000644000175000017500000004163312000052240014677 00000000000000/* 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, "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 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, "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 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, "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 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, "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; } /* `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) { u_short *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; } /* Route map `match tag' match statement. `arg' is TAG value */ static void * route_match_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `match tag' value. */ static void route_match_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag matching. */ static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_match_tag_compile, route_match_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) { u_short *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 `tag' compile function. Given string is converted to u_short. */ static void * route_set_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_set_tag_compile, route_set_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 <0-65535>", 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 <0-65535>", 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 <0-65535>", 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 <0-65535>", 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-0.99.22.4/ripngd/ripng_zebra.c0000644000175000017500000003373212177450262014174 00000000000000/* * RIPngd and zebra interface. * Copyright (C) 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "stream.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "ripngd/ripngd.h" /* All information about zebra. */ struct zclient *zclient = NULL; /* Callback prototypes for zebra client service. */ int ripng_interface_up (int, struct zclient *, zebra_size_t); int ripng_interface_down (int, struct zclient *, zebra_size_t); int ripng_interface_add (int, struct zclient *, zebra_size_t); int ripng_interface_delete (int, struct zclient *, zebra_size_t); int ripng_interface_address_add (int, struct zclient *, zebra_size_t); int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex, u_char metric) { struct zapi_ipv6 api; if (zclient->redist[ZEBRA_ROUTE_RIPNG]) { api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, p, &api); } } void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex) { struct zapi_ipv6 api; if (zclient->redist[ZEBRA_ROUTE_RIPNG]) { api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, p, &api); } } /* Zebra route add and delete treatment. */ static int ripng_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct in6_addr nexthop; struct prefix_ipv6 p; s = zclient->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, 16); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) ripng_redistribute_add (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop); 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 (! zclient->redist[type]) return CMD_SUCCESS; zclient->redist[type] = 0; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); ripng_redistribute_withdraw (type); return CMD_SUCCESS; } int ripng_redistribute_check (int type) { return (zclient->redist[type]); } 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 (zclient->redist[redist_type[i].type]) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, redist_type[i].type); zclient->redist[redist_type[i].type] = 0; /* 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") { zclient->redist[ZEBRA_ROUTE_RIPNG] = 1; return CMD_SUCCESS; } DEFUN (no_ripng_redistribute_ripng, no_ripng_redistribute_ripng_cmd, "no redistribute ripng", NO_STR "Redistribute information from another routing protocol\n" "RIPng route\n") { zclient->redist[ZEBRA_ROUTE_RIPNG] = 0; return CMD_SUCCESS; } DEFUN (ripng_redistribute_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); 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); 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); 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); 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 && zclient->redist[i]) { 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 (! zclient->redist[ZEBRA_ROUTE_RIPNG]) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE); return 1; } return 0; } /* Zebra node structure. */ static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", }; /* Initialize zebra structure and it's commands. */ void zebra_init () { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_RIPNG); zclient->interface_up = ripng_interface_up; zclient->interface_down = ripng_interface_down; zclient->interface_add = ripng_interface_add; zclient->interface_delete = ripng_interface_delete; zclient->interface_address_add = ripng_interface_address_add; zclient->interface_address_delete = ripng_interface_address_delete; zclient->ipv6_route_add = ripng_zebra_read_ipv6; zclient->ipv6_route_delete = ripng_zebra_read_ipv6; /* Install zebra node. */ install_node (&zebra_node, zebra_config_write); /* Install command element for zebra node. */ install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); install_default (ZEBRA_NODE); install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd); install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd); /* Install 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-0.99.22.4/ripngd/ripngd.c0000644000175000017500000023654512132522417013155 00000000000000/* 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, unsigned int *ifindex, int *hoplimit) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_addr dst; /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this point I can't determine size of cmsghdr */ char adata[1024]; /* Fill in message and iovec. */ msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = bufsize; /* If recvmsg fail return minus value. */ ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (cmsgptr = 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. */ rp->info = NULL; route_unlock_node (rp); /* Free RIPng routing information. */ ripng_info_free (rinfo); return 0; } /* Timeout RIPng routes. */ static int ripng_timeout (struct thread *t) { struct ripng_info *rinfo; struct route_node *rp; rinfo = THREAD_ARG (t); rinfo->t_timeout = NULL; /* Get route_node pointer. */ rp = rinfo->rp; /* - The garbage-collection timer is set for 120 seconds. */ RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); /* Delete this route from the kernel. */ ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, rinfo->ifindex); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service. */ rinfo->metric = RIPNG_METRIC_INFINITY; rinfo->flags &= ~RIPNG_RTF_FIB; /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); /* - The route change flag is to indicate that this entry has been changed. */ rinfo->flags |= RIPNG_RTF_CHANGED; /* - The output process is signalled to trigger a response. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); return 0; } 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_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; /* Input distribute-list filtering. */ if (ri->list[RIPNG_FILTER_IN]) { if (access_list_apply (ri->list[RIPNG_FILTER_IN], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIPNG_FILTER_IN]) { if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); 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 in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } static int ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; if (ri->list[RIPNG_FILTER_OUT]) { if (access_list_apply (ri->list[RIPNG_FILTER_OUT], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by distribute out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIPNG_FILTER_OUT]) { if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by prefix-list out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); 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 out", inet6_ntoa (p->prefix), p->prefixlen); 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; struct ripng_interface *ri; struct in6_addr *nexthop; u_char oldmetric; int same = 0; /* Make prefix structure. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; /* p.prefix = rte->addr; */ IPV6_ADDR_COPY (&p.prefix, &rte->addr); p.prefixlen = rte->prefixlen; /* Make sure mask is applied. */ /* XXX We have to check the prefix is valid or not before call apply_mask_ipv6. */ apply_mask_ipv6 (&p); /* Apply input filters. */ ri = ifp->info; ret = ripng_incoming_filter (&p, ri); if (ret < 0) return; /* Modify entry. */ if (ri->routemap[RIPNG_FILTER_IN]) { int ret; struct ripng_info newinfo; memset (&newinfo, 0, sizeof (struct ripng_info)); 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 */ 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; 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); /* Sanity check */ rinfo = rp->info; if (rinfo) { /* Redistributed route check. */ if (rinfo->type != ZEBRA_ROUTE_RIPNG && rinfo->metric != RIPNG_METRIC_INFINITY) 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) return; } if (rp->info == NULL) { /* Now, check to see whether there is already an explicit route for the destination prefix. If there is no such route, add this route to the routing table, unless the metric is infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIPNG_METRIC_INFINITY) { rinfo = ripng_info_new (); /* - Setting the destination prefix and length to those in the RTE. */ rp->info = rinfo; rinfo->rp = rp; /* - Setting the metric to the newly calculated metric (as described above). */ rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); /* - Set the next hop address to be the address of the router from which the datagram came or the next hop address specified by a next hop RTE. */ IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); rinfo->ifindex = ifp->ifindex; /* - Initialize the timeout for the route. If the garbage-collection timer is running for this route, stop it. */ ripng_timeout_update (rinfo); /* - Set the route change flag. */ rinfo->flags |= RIPNG_RTF_CHANGED; /* - Signal the output process to trigger an update (see section 2.5). */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); /* Finally, route goes into the kernel. */ rinfo->type = ZEBRA_ROUTE_RIPNG; rinfo->sub_type = RIPNG_ROUTE_RTE; ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex, rinfo->metric); rinfo->flags |= RIPNG_RTF_FIB; /* Aggregate check. */ ripng_aggregate_increment (rp, rinfo); } } else { rinfo = rp->info; /* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. If this datagram is from the same router as the existing route, reinitialize the timeout. */ same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) && (rinfo->ifindex == ifp->ifindex)); if (same) ripng_timeout_update (rinfo); /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old one; do the following actions: */ if ((same && rinfo->metric != rte->metric) || rte->metric < rinfo->metric) { /* - Adopt the route from the datagram. That is, put the new metric in, and adjust the next hop address (if necessary). */ oldmetric = rinfo->metric; rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); rinfo->ifindex = ifp->ifindex; /* Should a new route to this network be established while the garbage-collection timer is running, the new route will replace the one that is about to be deleted. In this case the garbage-collection timer must be cleared. */ if (oldmetric == RIPNG_METRIC_INFINITY && rinfo->metric < RIPNG_METRIC_INFINITY) { rinfo->type = ZEBRA_ROUTE_RIPNG; rinfo->sub_type = RIPNG_ROUTE_RTE; RIPNG_TIMER_OFF (rinfo->t_garbage_collect); if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric); rinfo->flags |= RIPNG_RTF_FIB; /* The aggregation counter needs to be updated because the prefixes, which are into the gc, have been removed from the aggregator (see ripng_timout). */ ripng_aggregate_increment (rp, rinfo); } /* Update nexthop and/or metric value. */ if (oldmetric != RIPNG_METRIC_INFINITY) { ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric); rinfo->flags |= RIPNG_RTF_FIB; if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); } /* - Set the route change flag and signal the output process to trigger an update. */ rinfo->flags |= RIPNG_RTF_CHANGED; ripng_event (RIPNG_TRIGGERED_UPDATE, 0); /* - If the new metric is infinity, start the deletion process (described above); */ if (rinfo->metric == RIPNG_METRIC_INFINITY) { /* If the new metric is infinity, the deletion process begins for the route, which is no longer used for routing packets. Note that the deletion process is started only when the metric is first set to infinity. If the metric was already infinity, then a new deletion process is not started. */ if (oldmetric != RIPNG_METRIC_INFINITY) { /* - The garbage-collection timer is set for 120 seconds. */ RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); RIPNG_TIMER_OFF (rinfo->t_timeout); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service.*/ ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); rinfo->flags &= ~RIPNG_RTF_FIB; /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); /* - The route change flag is to indicate that this entry has been changed. */ /* - The output process is signalled to trigger a response. */ ; /* Above processes are already done previously. */ } } else { /* otherwise, re-initialize the timeout. */ ripng_timeout_update (rinfo); } } /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } } /* Add redistributed route to RIPng table. */ void ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, unsigned int ifindex, struct in6_addr *nexthop) { struct route_node *rp; struct ripng_info *rinfo; /* Redistribute route */ if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; #if defined (MUSICA) || defined (LINUX) /* XXX As long as the RIPng redistribution is applied to all the connected * routes, one needs to filter the ::/96 prefixes. * However it could be a wanted case, it will be removed soon. */ if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) return; #endif /* MUSICA or LINUX */ rp = route_node_get (ripng->table, (struct prefix *) p); rinfo = rp->info; if (rinfo) { 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; } } RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_OFF (rinfo->t_garbage_collect); /* Tells the other daemons about the deletion of * this RIPng route **/ if (ripng_route_rte (rinfo)) ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, rinfo->metric); rp->info = NULL; ripng_info_free (rinfo); route_unlock_node (rp); } rinfo = ripng_info_new (); rinfo->type = type; rinfo->sub_type = sub_type; rinfo->ifindex = ifindex; rinfo->metric = 1; rinfo->rp = rp; if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop)) rinfo->nexthop = *nexthop; rinfo->flags |= RIPNG_RTF_FIB; rp->info = rinfo; /* Aggregate check. */ ripng_aggregate_increment (rp, rinfo); rinfo->flags |= RIPNG_RTF_CHANGED; 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, unsigned int ifindex) { struct route_node *rp; struct ripng_info *rinfo; if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; #if defined (MUSICA) || defined (LINUX) /* XXX As long as the RIPng redistribution is applied to all the connected * routes, one needs to filter the ::/96 prefixes. * However it could be a wanted case, it will be removed soon. */ if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) || (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) return; #endif /* MUSICA or LINUX */ rp = route_node_lookup (ripng->table, (struct prefix *) p); if (rp) { rinfo = rp->info; if (rinfo != NULL && rinfo->type == type && rinfo->sub_type == sub_type && rinfo->ifindex == ifindex) { /* 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); } } } /* Withdraw redistributed route. */ void ripng_redistribute_withdraw (int type) { struct route_node *rp; struct ripng_info *rinfo; if (!ripng) return; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { 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 = 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; unsigned int ifindex; struct interface *ifp; int hoplimit = -1; /* Check ripng is active and alive. */ assert (ripng != NULL); assert (ripng->sock >= 0); /* Fetch thread data and set read pointer to empty for event managing. `sock' sould be same as ripng->sock. */ sock = THREAD_FD (thread); ripng->t_read = NULL; /* Add myself to the next event. */ ripng_event (RIPNG_READ, sock); /* Read RIPng packet. */ len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), STREAM_SIZE (ripng->ibuf), &from, &ifindex, &hoplimit); if (len < 0) { zlog_warn ("RIPng recvfrom failed: %s.", 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; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) if (rinfo->flags & RIPNG_RTF_CHANGED) rinfo->flags &= ~RIPNG_RTF_CHANGED; } /* Regular update of RIPng route. Send all routing formation to RIPng enabled interface. */ 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; 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 ((rinfo = rp->info) != 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_outgoing_filter (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. */ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && rinfo->ifindex == ifp->ifindex) 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) { if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && 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_outgoing_filter (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 ((rand () % (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; 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 ((rinfo = rp->info) != NULL) { 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); 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); } 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; } /* 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); /* 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_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); if (alist) ri->list[RIPNG_FILTER_IN] = alist; else ri->list[RIPNG_FILTER_IN] = NULL; } else ri->list[RIPNG_FILTER_IN] = NULL; if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); if (alist) ri->list[RIPNG_FILTER_OUT] = alist; else ri->list[RIPNG_FILTER_OUT] = NULL; } else ri->list[RIPNG_FILTER_OUT] = NULL; if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); if (plist) ri->prefix[RIPNG_FILTER_IN] = plist; else ri->prefix[RIPNG_FILTER_IN] = NULL; } else ri->prefix[RIPNG_FILTER_IN] = NULL; if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); if (plist) ri->prefix[RIPNG_FILTER_OUT] = plist; else ri->prefix[RIPNG_FILTER_OUT] = NULL; } else ri->prefix[RIPNG_FILTER_OUT] = NULL; } void ripng_distribute_update_interface (struct interface *ifp) { struct distribute *dist; dist = distribute_lookup (ifp->name); if (dist) ripng_distribute_update (dist); } /* Update all interface's distribute list. */ 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 (struct access_list *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; if (ripng) { /* Clear RIPng routes */ for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((rinfo = rp->info) != NULL) { if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && (rinfo->sub_type == RIPNG_ROUTE_RTE)) ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, rinfo->metric); RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_OFF (rinfo->t_garbage_collect); rp->info = NULL; route_unlock_node (rp); ripng_info_free(rinfo); } } /* 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. */ srand (time (NULL)); /* Install RIPNG_NODE. */ install_node (&cmd_ripng_node, ripng_config_write); /* Install ripng commands. */ install_element (VIEW_NODE, &show_ipv6_ripng_cmd); install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd); install_element (ENABLE_NODE, &show_ipv6_ripng_cmd); install_element (ENABLE_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); 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-0.99.22.4/ripngd/ripngd.conf.sample0000644000175000017500000000060612000052240015105 00000000000000! -*- 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-0.99.22.4/ripngd/ripngd.h0000644000175000017500000002610212132522417013144 00000000000000/* * 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; /* 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_short 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. */ unsigned int ifindex; /* Metric of this route. */ u_char metric; /* Tag field of RIPng packet.*/ u_int16_t tag; /* For aggregation. */ unsigned int suppress; /* Flags of RIPng route. */ #define RIPNG_RTF_FIB 1 #define RIPNG_RTF_CHANGED 2 u_char flags; /* Garbage collect timer. */ struct thread *t_timeout; struct thread *t_garbage_collect; /* Route-map features - this variables can be changed. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; u_short 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) /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) /* 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 (void); 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 *, unsigned int, struct in6_addr *); extern void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, unsigned int); 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 prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex, u_char metric); extern void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex); 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); extern int ripng_interface_down (int command, struct zclient *, zebra_size_t); extern int ripng_interface_add (int command, struct zclient *, zebra_size_t); extern int ripng_interface_delete (int command, struct zclient *, zebra_size_t); extern int ripng_interface_address_add (int command, struct zclient *, zebra_size_t); extern int ripng_interface_address_delete (int command, struct zclient *, zebra_size_t); extern int ripng_network_write (struct vty *, int); #endif /* _ZEBRA_RIPNG_RIPNGD_H */ quagga-0.99.22.4/solaris/0000755000175000017500000000000012211704577011767 500000000000000quagga-0.99.22.4/solaris/Makefile.am0000644000175000017500000001034412045513244013737 00000000000000# 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-0.99.22.4/solaris/Makefile.in0000644000175000017500000003755112211704502013753 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 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) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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 .PRECIOUS: 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 TAGS: ctags: 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 \ 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 uninstall uninstall-am .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-0.99.22.4/solaris/README.txt0000644000175000017500000001542212000052240013364 00000000000000To 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-0.99.22.4/solaris/depend.daemons.in0000644000175000017500000000036112000052240015076 00000000000000P 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-0.99.22.4/solaris/depend.dev.in0000644000175000017500000000011712000052240014225 00000000000000P QUAGGAlibs Quagga common runtime libraries @PACKAGE_VERSION@,REV=@CONFDATE@ quagga-0.99.22.4/solaris/depend.doc.in0000644000175000017500000000003612000052240014214 00000000000000P SUNWdoc Documentation Tools quagga-0.99.22.4/solaris/depend.libs.in0000644000175000017500000000025512000052240014403 00000000000000P SUNWcslr Core Solaris Libraries (Root) P SUNWcsl Core Solaris, (Shared Libs) P SUNWlibmsr Math & Microtasking Libraries (Root) R QUAGGAdaemons Quagga daemons R QUAGGAdev quagga-0.99.22.4/solaris/depend.smf.in0000644000175000017500000000033712000052240014240 00000000000000P 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-0.99.22.4/solaris/pkginfo.daemons.tmpl.in0000644000175000017500000000010312000052240016241 00000000000000PKG="QUAGGAdaemons" NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ daemons" quagga-0.99.22.4/solaris/pkginfo.dev.tmpl.in0000644000175000017500000000011012000052240015367 00000000000000PKG=QUAGGAdev NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ development files" quagga-0.99.22.4/solaris/pkginfo.doc.tmpl.in0000644000175000017500000000010312000052240015360 00000000000000PKG=QUAGGAdoc NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ documentation" quagga-0.99.22.4/solaris/pkginfo.libs.tmpl.in0000644000175000017500000000011712000052240015551 00000000000000PKG=QUAGGAlibs NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ common runtime libraries" quagga-0.99.22.4/solaris/pkginfo.smf.tmpl.in0000644000175000017500000000010312000052240015400 00000000000000PKG="QUAGGAsmf" NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ SMF support" quagga-0.99.22.4/solaris/pkginfo.tmpl.in0000644000175000017500000000041412000052240014621 00000000000000ARCH="@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-0.99.22.4/solaris/prototype.daemons.in0000644000175000017500000000261312000052240015706 00000000000000i 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-0.99.22.4/solaris/prototype.dev.in0000644000175000017500000001145112000052240015036 00000000000000i 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-0.99.22.4/solaris/prototype.doc.in0000644000175000017500000000203012000052240015016 00000000000000i 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-0.99.22.4/solaris/prototype.libs.in0000644000175000017500000000133712000052240015213 00000000000000i 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-0.99.22.4/solaris/prototype.smf.in0000644000175000017500000000054712000052240015051 00000000000000i 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-0.99.22.4/solaris/quagga.init.in0000755000175000017500000001773512045513244014460 00000000000000#!/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} } # certain daemons need zebra routeadm_zebra_enable () { if [ "$DAEMON" = "zebra" ]; then return fi enable_zebra=`/usr/bin/svcprop -p \ routing/enable_zebra $SMF_FMRI 2> /dev/null` if [ "$enable_zebra" != "false" ]; then zenabled=`/usr/bin/svcprop -p general/enabled zebra:quagga` zenabledt=`/usr/bin/svcprop -p general_ovr/enabled zebra:quagga` if [ "$zenabled" = "true" -o "$zenabledt" = "true" ]; then /usr/sbin/svcadm disable zebra:quagga /usr/sbin/svcadm enable -st zebra:quagga else /usr/sbin/svcadm enable -st zebra:quagga fi if [ "$?" != "0" ]; then echo "Could not enable zebra:quagga" exit $SMF_EXIT_ERR_FATAL fi fi } # 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 [ -z "$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`; routeadm_zebra_enable $DAEMON; else if [ $# -gt 0 ] ; then shift DAEMON_ARGS="$@" fi fi upgrade_config "$DAEMON" if [ ! -f "@sysconfdir@/${DAEMON}.conf" ] ; then echo "Could not find config file, @sysconfdir@/${DAEMON}.conf" 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-0.99.22.4/solaris/quagga.xml.in0000644000175000017500000005753612000052240014276 00000000000000 quagga-0.99.22.4/tests/0000755000175000017500000000000012211704577011455 500000000000000quagga-0.99.22.4/tests/Makefile.am0000644000175000017500000000342712211704467013435 00000000000000INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) if BGPD TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath else TESTS_BGPD = endif noinst_PROGRAMS = testsig testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest \ $(TESTS_BGPD) testsig_SOURCES = test-sig.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 testsig_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 quagga-0.99.22.4/tests/Makefile.in0000644000175000017500000006073712211704502013443 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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@ noinst_PROGRAMS = testsig$(EXEEXT) testbuffer$(EXEEXT) \ testmemory$(EXEEXT) heavy$(EXEEXT) heavywq$(EXEEXT) \ heavythread$(EXEEXT) testprivs$(EXEEXT) teststream$(EXEEXT) \ testchecksum$(EXEEXT) tabletest$(EXEEXT) $(am__EXEEXT_1) subdir = tests DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) 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) PROGRAMS = $(noinst_PROGRAMS) am_aspathtest_OBJECTS = aspath_test.$(OBJEXT) aspathtest_OBJECTS = $(am_aspathtest_OBJECTS) aspathtest_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la 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_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_testmemory_OBJECTS = test-memory.$(OBJEXT) testmemory_OBJECTS = $(am_testmemory_OBJECTS) testmemory_DEPENDENCIES = ../lib/libzebra.la am_testprivs_OBJECTS = test-privs.$(OBJEXT) testprivs_OBJECTS = $(am_testprivs_OBJECTS) testprivs_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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(aspathtest_SOURCES) $(ecommtest_SOURCES) $(heavy_SOURCES) \ $(heavythread_SOURCES) $(heavywq_SOURCES) $(tabletest_SOURCES) \ $(testbgpcap_SOURCES) $(testbgpmpath_SOURCES) \ $(testbgpmpattr_SOURCES) $(testbuffer_SOURCES) \ $(testchecksum_SOURCES) $(testmemory_SOURCES) \ $(testprivs_SOURCES) $(testsig_SOURCES) $(teststream_SOURCES) DIST_SOURCES = $(aspathtest_SOURCES) $(ecommtest_SOURCES) \ $(heavy_SOURCES) $(heavythread_SOURCES) $(heavywq_SOURCES) \ $(tabletest_SOURCES) $(testbgpcap_SOURCES) \ $(testbgpmpath_SOURCES) $(testbgpmpattr_SOURCES) \ $(testbuffer_SOURCES) $(testchecksum_SOURCES) \ $(testmemory_SOURCES) $(testprivs_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 ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) @BGPD_FALSE@TESTS_BGPD = @BGPD_TRUE@TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath testsig_SOURCES = test-sig.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 testsig_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 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 tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/Makefile .PRECIOUS: 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-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 aspathtest$(EXEEXT): $(aspathtest_OBJECTS) $(aspathtest_DEPENDENCIES) $(EXTRA_aspathtest_DEPENDENCIES) @rm -f aspathtest$(EXEEXT) $(LINK) $(aspathtest_OBJECTS) $(aspathtest_LDADD) $(LIBS) ecommtest$(EXEEXT): $(ecommtest_OBJECTS) $(ecommtest_DEPENDENCIES) $(EXTRA_ecommtest_DEPENDENCIES) @rm -f ecommtest$(EXEEXT) $(LINK) $(ecommtest_OBJECTS) $(ecommtest_LDADD) $(LIBS) heavy$(EXEEXT): $(heavy_OBJECTS) $(heavy_DEPENDENCIES) $(EXTRA_heavy_DEPENDENCIES) @rm -f heavy$(EXEEXT) $(LINK) $(heavy_OBJECTS) $(heavy_LDADD) $(LIBS) heavythread$(EXEEXT): $(heavythread_OBJECTS) $(heavythread_DEPENDENCIES) $(EXTRA_heavythread_DEPENDENCIES) @rm -f heavythread$(EXEEXT) $(LINK) $(heavythread_OBJECTS) $(heavythread_LDADD) $(LIBS) heavywq$(EXEEXT): $(heavywq_OBJECTS) $(heavywq_DEPENDENCIES) $(EXTRA_heavywq_DEPENDENCIES) @rm -f heavywq$(EXEEXT) $(LINK) $(heavywq_OBJECTS) $(heavywq_LDADD) $(LIBS) tabletest$(EXEEXT): $(tabletest_OBJECTS) $(tabletest_DEPENDENCIES) $(EXTRA_tabletest_DEPENDENCIES) @rm -f tabletest$(EXEEXT) $(LINK) $(tabletest_OBJECTS) $(tabletest_LDADD) $(LIBS) testbgpcap$(EXEEXT): $(testbgpcap_OBJECTS) $(testbgpcap_DEPENDENCIES) $(EXTRA_testbgpcap_DEPENDENCIES) @rm -f testbgpcap$(EXEEXT) $(LINK) $(testbgpcap_OBJECTS) $(testbgpcap_LDADD) $(LIBS) testbgpmpath$(EXEEXT): $(testbgpmpath_OBJECTS) $(testbgpmpath_DEPENDENCIES) $(EXTRA_testbgpmpath_DEPENDENCIES) @rm -f testbgpmpath$(EXEEXT) $(LINK) $(testbgpmpath_OBJECTS) $(testbgpmpath_LDADD) $(LIBS) testbgpmpattr$(EXEEXT): $(testbgpmpattr_OBJECTS) $(testbgpmpattr_DEPENDENCIES) $(EXTRA_testbgpmpattr_DEPENDENCIES) @rm -f testbgpmpattr$(EXEEXT) $(LINK) $(testbgpmpattr_OBJECTS) $(testbgpmpattr_LDADD) $(LIBS) testbuffer$(EXEEXT): $(testbuffer_OBJECTS) $(testbuffer_DEPENDENCIES) $(EXTRA_testbuffer_DEPENDENCIES) @rm -f testbuffer$(EXEEXT) $(LINK) $(testbuffer_OBJECTS) $(testbuffer_LDADD) $(LIBS) testchecksum$(EXEEXT): $(testchecksum_OBJECTS) $(testchecksum_DEPENDENCIES) $(EXTRA_testchecksum_DEPENDENCIES) @rm -f testchecksum$(EXEEXT) $(LINK) $(testchecksum_OBJECTS) $(testchecksum_LDADD) $(LIBS) testmemory$(EXEEXT): $(testmemory_OBJECTS) $(testmemory_DEPENDENCIES) $(EXTRA_testmemory_DEPENDENCIES) @rm -f testmemory$(EXEEXT) $(LINK) $(testmemory_OBJECTS) $(testmemory_LDADD) $(LIBS) testprivs$(EXEEXT): $(testprivs_OBJECTS) $(testprivs_DEPENDENCIES) $(EXTRA_testprivs_DEPENDENCIES) @rm -f testprivs$(EXEEXT) $(LINK) $(testprivs_OBJECTS) $(testprivs_LDADD) $(LIBS) testsig$(EXEEXT): $(testsig_OBJECTS) $(testsig_DEPENDENCIES) $(EXTRA_testsig_DEPENDENCIES) @rm -f testsig$(EXEEXT) $(LINK) $(testsig_OBJECTS) $(testsig_LDADD) $(LIBS) teststream$(EXEEXT): $(teststream_OBJECTS) $(teststream_DEPENDENCIES) $(EXTRA_teststream_DEPENDENCIES) @rm -f teststream$(EXEEXT) $(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)/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)/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-memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-privs.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@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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: 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 \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS cscopelist ctags 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 uninstall uninstall-am # 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-0.99.22.4/tests/aspath_test.c0000644000175000017500000012045212177450262014064 00000000000000#include #include "vty.h" #include "stream.h" #include "privs.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 } } }; /* */ 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, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 10, }, 3, }, /* 1 */ { "length too short", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 8, }, 3, }, /* 2 */ { "length too long", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 12, }, 3, }, /* 3 */ { "incorrect flag", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 10, }, 3, }, /* 4 */ { "as4_path, with as2 format data", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, 3, }, /* 5 */ { "as4, with incorrect attr length", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, 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, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 18, }, 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, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 16, }, 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, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 20, }, 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, { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 22, }, 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, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 18, }, 3, }, /* 11 */ { "4b AS4_PATH w/o AS_PATH", &test_segments[6], NULL, AS4_DATA, 0, PEER_CAP_AS4_ADV, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, 3, }, /* 12 */ { "4b AS4_PATH: confed", &test_segments[6], "8466 3 52737 4096 (123 456 789)", AS4_DATA, 0, PEER_CAP_AS4_ADV, { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, 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, doesnt: %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-0.99.22.4/tests/bgp_capability_test.c0000644000175000017500000004166112177450262015561 00000000000000#include #include "vty.h" #include "stream.h" #include "privs.h" #include "memory.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, }, /* 20 */ { "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, }, /* 21 */ { "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, }, 16, SHOULD_PARSE, }, /* 22 */ { "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, }, 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-0.99.22.4/tests/bgp_mp_attr_test.c0000644000175000017500000004264512177450262015111 00000000000000#include #include "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.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-MLVPN", "IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs", { /* 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 */ }, (4 + 12 + 1 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, 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-MLVPN", "IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs", { /* 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 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; /* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { int ret; int oldfailed = failed; struct attr attr = { }; struct bgp_nlri nlri = { }; struct bgp_attr_parser_args attr_args = { .peer = peer, .length = t->len, .total = 1, .attr = &attr, .type = BGP_ATTR_MP_REACH_NLRI, .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) ret = bgp_mp_reach_parse (&attr_args, &nlri); else ret = bgp_mp_unreach_parse (&attr_args, &nlri); if (!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 ("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 = "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_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-0.99.22.4/tests/bgp_mpath_test.c0000644000175000017500000003254412177450262014551 00000000000000/* $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 "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 peer test_mp_list_peer[] = { { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, }; 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 = listhead(&mp_list); 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; struct bgp_maxpaths_cfg mp_cfg = { 3, 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, &mp_cfg); 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, &mp_cfg); 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 (); 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) { 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-0.99.22.4/tests/ecommunity_test.c0000644000175000017500000000571212177450262014776 00000000000000#include #include "vty.h" #include "stream.h" #include "privs.h" #include "memory.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 (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-0.99.22.4/tests/heavy-thread.c0000644000175000017500000000665212132522417014124 00000000000000/* * $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" 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-0.99.22.4/tests/heavy-wq.c0000644000175000017500000001006712132522417013277 00000000000000/* * 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 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-0.99.22.4/tests/heavy.c0000644000175000017500000000532312132522417012651 00000000000000/* * $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 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-0.99.22.4/tests/main.c0000644000175000017500000001042412132522417012457 00000000000000/* * $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; 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; struct thread thread; 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 (); sort_node (); /* 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. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ exit (0); } quagga-0.99.22.4/tests/table_test.c0000644000175000017500000002733412177450262013700 00000000000000/* $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-0.99.22.4/tests/test-buffer.c0000644000175000017500000000122212132522417013755 00000000000000#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-0.99.22.4/tests/test-checksum.c0000644000175000017500000002537112177450262014330 00000000000000#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 /* Accumulator phase of checksum */ static struct acc_vals accumulate (u_char *buffer, testsz_t len, testoff_t off) { u_int8_t *p; u_int16_t *csum; int i, partial_len; struct acc_vals ret; csum = (u_int16_t *) (buffer + off); *(csum) = 0; p = buffer; ret.c0 = 0; ret.c1 = 0; while (len != 0) { partial_len = MIN(len, MODX); for (i = 0; i < partial_len; i++) { ret.c0 = ret.c0 + *(p++); ret.c1 += ret.c0; } ret.c0 = ret.c0 % 255; ret.c1 = ret.c1 % 255; len -= partial_len; } return ret; } /* 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-0.99.22.4/tests/test-memory.c0000644000175000017500000000532312132522417014022 00000000000000#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-0.99.22.4/tests/test-privs.c0000644000175000017500000000654312132522417013662 00000000000000/* * $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-0.99.22.4/tests/test-sig.c0000644000175000017500000000172012177450262013300 00000000000000#include #include #include "lib/log.h" #include "lib/memory.h" void sighup (void) { printf ("processed hup\n"); } void sigusr1 (void) { printf ("processed usr1\n"); } 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; struct thread t; 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); while (thread_fetch (master, &t)) thread_call (&t); exit (0); } quagga-0.99.22.4/tests/test-stream.c0000644000175000017500000000200312132522417013775 00000000000000#include #include #include static long int ham = 0xdeadbeefdeadbeef; struct thread_master *master; static void print_stream (struct stream *s) { size_t getp = stream_get_getp (s); printf ("endp: %ld, readable: %ld, writeable: %ld\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%lx\n", stream_getq (s)); return 0; } quagga-0.99.22.4/tools/0000755000175000017500000000000012211704576011452 500000000000000quagga-0.99.22.4/tools/mrlg.cgi0000755000175000017500000002176612000052240013012 00000000000000#!/usr/bin/perl ## ## Zebra Looking Glass version 1.0 ## 01 FEB 2000 ## Copyright (C) 2000 John W. Fraizer III ## *All* copyright notices must remain in place to use this code. ## ## The latest version of this code is available at: ## ftp://ftp.enterzone.net/looking-glass/ ## ## ## This file is part of GNU Zebra. ## ## GNU Zebra is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by the ## Free Software Foundation; either version 2, or (at your option) any ## later version. ## ## GNU Zebra is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with GNU Zebra; see the file COPYING. If not, write to the ## Free Software Foundation, Inc., 59 Temple Place - Suite 330, ## Boston, MA 02111-1307, USA. require 5.002; use POSIX; use Net::Telnet (); ## Set the URL for your site. $url="http://www.sample.com/mrlg.cgi"; ## Set your router variables in sub set_router and modify the selections in Main to match. ############################################################ #Main ############################################################ { ## Set the router default @Form{'router'} = "router1"; ## Get the form results now so we can override the default router get_form(); print "Content-type: text/html\n\n"; print ' Multi-Router Looking Glass for Zebra

Multi-Router Looking Glass for Zebra

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

Query:
show ip bgp
show ip bgp summary
show ip route
show interface
show ipv6 bgp
show ipv6 bgp summary
show ipv6 route

Argument:
'; ## Set up the address, pw and ports, etc for the selected router. set_router(); ## Set up which command is to be executed (and then execute it!) set_command(); print '

Multi-Router Looking Glass for Zebra version 1.0
Written by: John Fraizer - EnterZone, Inc
Source code: ftp://ftp.enterzone.net/looking-glass/ '; ## All done! exit (0); } ############################################################ sub get_form ############################################################ { #read STDIN read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); # Split the name-value pairs @pairs = split(/&/, $buffer); # For each name-value pair: foreach $pair (@pairs) { # Split the pair up into individual variables. local($name, $value) = split(/=/, $pair); # Decode the form encoding on the name and value variables. $name =~ tr/+/ /; $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # If they try to include server side includes, erase them, so they # aren't a security risk if the html gets returned. Another # security hole plugged up. $value =~ s///g; @Form{$name} = $value ; } } ############################################################ sub set_router ############################################################ ## $server is the IP address of the router running zebra ## $login_pass is the password of the router ## $bgpd is the port that bgpd will answer on ## $zebra is the port that zebra will answer on ## if $zebra is "", it will disable sh ip route and sh int for that router. ## if $full_tables is set to "1" for a router, full BGP and IP ROUTE table dumps will be allowed via the looking glass. ## This is a BAD thing to do if you have multiple full views on a router. That's why the option is there. { if ($Form{'router'} eq 'router1') { $server = '10.1.1.1'; $login_pass = 'zebra'; $bgpd = "2605"; $zebra = ""; $full_tables=1; } elsif ($Form{'router'} eq 'router2') { $server = '10.1.1.2'; $login_pass = 'zebra'; $bgpd = "2605"; $zebra = "2601"; } elsif ($Form{'router'} eq 'router3') { $server = '10.1.1.3'; $login_pass = 'zebra'; $bgpd = "2605"; $zebra = "2601"; $full_tables=1; } elsif ($Form{'router'} eq 'router4') { $server = '10.1.1.4'; $login_pass = 'zebra'; $bgpd = "2605"; $zebra = "2601"; } } ############################################################ sub set_command ############################################################ { if ($Form{'query'} eq '1') { sh_ip_bgp('ip'); } elsif ($Form{'query'} eq '2') { sh_ip_bgp_sum('ip'); } if ($Form{'query'} eq '3') { sh_ip_route('ip'); } if ($Form{'query'} eq '4') { sh_int(); } if ($Form{'query'} eq '5') { sh_ip_bgp('ipv6'); } if ($Form{'query'} eq '6') { sh_ip_bgp_sum('ipv6'); } if ($Form{'query'} eq '7') { sh_ip_route('ipv6'); } } ############################################################ sub sh_ip_bgp ############################################################ { my $protocol = shift(@_); $port = $bgpd; if ($protocol ne 'ip' && $protocol ne 'ipv6') { print "Invalid protocol: $protocol\n"; print "protocol must be 'ip' or 'ipv6'\n\n"; return; } $command = "show $protocol bgp $Form{'arg'}"; if ($Form{'arg'} eq '') { if ($full_tables eq '1') { execute_command(); } else { print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; } } else { execute_command(); } } ############################################################ sub sh_ip_bgp_sum ############################################################ { my $protocol = shift(@_); $port = $bgpd; if ($protocol ne 'ip' && $protocol ne 'ipv6') { print "Invalid protocol: $protocol\n"; print "protocol must be 'ip' or 'ipv6'\n\n"; return; } $command = "show $protocol bgp summary"; execute_command(); } ############################################################ sub sh_ip_route ############################################################ { if ($zebra eq '') { print "Sorry. The show ip route command is disabled for this router." } else { $port = $zebra; my $protocol = shift(@_); if ($protocol ne 'ip' && $protocol ne 'ipv6') { print "Invalid protocol: $protocol\n"; print "protocol must be 'ip' or 'ipv6'\n\n"; return; } $command = "show $protocol route $Form{'arg'}"; if ($Form{'arg'} eq '') { if ($full_tables eq '1') { execute_command(); } else { print "Sorry. Displaying the FULL routing table would put too much load on the router!\n\n"; } } else { execute_command(); } } } ############################################################ sub sh_int ############################################################ { if ($zebra eq '') { print "Sorry. The show interface command is disabled for this router." } else { $port = $zebra; $command = "show interface $Form{'arg'}"; execute_command(); } } ############################################################ sub execute_command ############################################################ ## This code is based on: ## ## Zebra interactive console ## Copyright (C) 2000 Vladimir B. Grebenschikov ## { print "Executing command = $command"; # my $port = ($opt_z ? 'zebra' : 0) || # ($opt_b ? 'bgpd' : 0) || # ($opt_o ? 'ospfd' : 0) || # ($opt_r ? 'ripd' : 0) || 'bgpd'; my $cmd = $command; my $t = new Net::Telnet (Timeout => 10, Prompt => '/[\>\#] $/', Port => $port); $t->open ($server); $t->cmd ($login_pass); if ($cmd) { docmd ($t, $cmd); } } ############################################################ sub docmd ############################################################ { my ($t, $cmd) = @_; my @lines = $t->cmd ($cmd); print "
\n";
  print join ('', grep (!/[\>\#] $/, @lines)), "\n";
  print "
"; } quagga-0.99.22.4/tools/multiple-bgpd.sh0000644000175000017500000000434512101110036014455 00000000000000#!/bin/bash # Public domain, not copyrighted.. NUM=5 VTYBASE=2610 ASBASE=64560 BGPD=/path/to/bgpd PREFIX=192.168.145. #PREFIX=3ffe:123:456:: ADDRPLEN=32 CONFBASE=/tmp PIDBASE=/var/run/quagga CHOWNSTR=quagga:quagga for H in `seq 1 ${NUM}` ; do CONF="${CONFBASE}"/bgpd${H}.conf ADDR=${PREFIX}${H} if [ ! -e "$CONF" ] ; then # This sets up a ring of bgpd peerings NEXT=$(( ($H % ${NUM}) + 1 )) PREV=$(( (($H + $NUM - 2) % ${NUM}) + 1 )) NEXTADDR="${PREFIX}${NEXT}" NEXTAS=$((${ASBASE} + $NEXT)) PREVADDR="${PREFIX}${PREV}" PREVAS=$((${ASBASE} + $PREV)) ASN=$((64560+${H})) # Edit config to suit. cat > "$CONF" <<- EOF password whatever service advanced-vty ! router bgp ${ASN} bgp router-id ${ADDR} network 10.${H}.1.0/24 pathlimit 1 network 10.${H}.2.0/24 pathlimit 2 network 10.${H}.3.0/24 pathlimit 3 neighbor default peer-group neighbor default update-source ${ADDR} neighbor default capability orf prefix-list both neighbor default soft-reconfiguration inbound neighbor default route-map test out neighbor ${NEXTADDR} remote-as ${NEXTAS} neighbor ${NEXTADDR} peer-group default neighbor ${PREVADDR} remote-as ${PREVAS} neighbor ${PREVADDR} peer-group default ! address-family ipv6 network 3ffe:${H}::/48 network 3ffe:${H}:1::/48 pathlimit 1 network 3ffe:${H}:2::/48 pathlimit 3 network 3ffe:${H}:3::/48 pathlimit 3 neighbor default activate neighbor default capability orf prefix-list both neighbor default default-originate neighbor default route-map test out neighbor ${NEXTADDR} peer-group default neighbor ${PREVADDR} peer-group default 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 ! end EOF chown ${CHOWNSTR} "$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 ${BGPD} -i "${PIDBASE}"/bgpd${H}.pid \ -l ${ADDR} \ -f "${CONF}" \ -P $((${VTYBASE}+${H})) \ -d done quagga-0.99.22.4/tools/rrcheck.pl0000644000175000017500000000560312177450262013355 00000000000000#!/usr/bin/env perl ## ## Read BGPd logfile and lookup RR's whois database. ## ## Copyright (c) 1997 Kunihiro Ishiguro ## use Socket; ## Configuration variables $whois_host = "whois.jpix.ad.jp"; #$logfile = "/usr/local/sbin/logfile" $logfile = shift || die "Please specify filename"; ## mail routine { local ($prefix, $origin); open (LOG, $logfile) || die "can't open $logfile"; $index = ''; while ($index) { $index = ; if ($index =~ /[bgpd]/) { break; } } while () { if (/([\d\.\/]+)\s+([\d\.]+)\s+(\d+)\s+(\d+)\s+([\d ]+)\s+[ie\?]/) { $prefix = $1; $nexthop = $2; $med = $3; $dummy = $4; $aspath = $5; ($origin) = ($aspath =~ /([\d]+)$/); print "$nexthop [$origin] $prefix $aspath "; $ret = &whois_check ($prefix, $origin); if ($ret == 0) { print "Check OK\n"; } elsif ($ret == 1){ print "AS orgin mismatch\n"; } else { print "prefix doesn't exist \n"; } } } } sub whois_check { local ($prefix, $origin) = @_; local ($rr_prefix, $rr_origin) = (); local (@result); $origin = "AS" . $origin; @result = &whois ($prefix); $prefix_match = 0; foreach (@result) { if (/^route:.*\s([\d\.\/]+)$/) { $rr_prefix = $1; } if (/^origin:.*\s(AS[\d]+)$/) { $rr_origin = $1; if ($prefix eq $rr_prefix and $origin eq $rr_origin) { return 0; } elsif ($prefix eq $rr_prefix) { $prefix_match = 1; } } } # alarm_mail ($prefix, $origin, @result); if ($prefix_match) { return 1; } else { return 2; } } ## get port of whois sub get_whois_port { local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); return ($port, $proto); } ## whois lookup sub whois { local ($query) = @_; local ($port, $proto) = &get_whois_port; local (@result); if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { $address = pack ("C4",split(/\./,$host)); } else { $address = (gethostbyname ($whois_host))[4]; } socket (SOCKET, PF_INET, SOCK_STREAM, $proto); if (connect (SOCKET, sockaddr_in ($port, $address))) { local ($oldhandle) = select (SOCKET); $| = 1; select($oldhandle); print SOCKET "$query\r\n"; @result = ; return @result; } } ## sub alarm_mail { local ($prefix, $origin, @result) = @_; open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; print MAIL "From: root\@rr1.jpix.ad.jp\n"; print MAIL "Subject: RR $origin $prefix\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; print MAIL "RR Lookup Error Report\n"; print MAIL "======================\n"; print MAIL "Announced route : $prefix from $origin\n\n"; print MAIL "@result"; close MAIL; } quagga-0.99.22.4/tools/rrlookup.pl0000644000175000017500000000546412177450262013616 00000000000000#!/usr/bin/env perl ## ## Read BGPd logfile and lookup RR's whois database. ## ## Copyright (c) 1997 Kunihiro Ishiguro ## use Socket; ## Configuration variables $whois_host = "whois.jpix.ad.jp"; #$mail_address = "toshio\@iri.co.jp"; $mail_address = "kunihiro\@zebra.org"; $mailer = "/usr/sbin/sendmail -oi"; #$logfile = "/usr/local/sbin/logfile" $logfile = "logfile"; $lookuplog = "lookuplog"; ## mail routine { local ($prefix, $origin); open (LOG, $logfile) || die "can't open $logfile"; open (LOOKUP, ">$lookuplog") || die "can't open $lookuplog"; for (;;) { while () { if (/Update\S+ ([\d\.\/]+) .* (\d+) [ie\?]/) { $prefix = $1; $origin = $2; $ret = &whois_check ($prefix, $origin); if ($ret) { print LOOKUP "$prefix AS$origin : Check OK\n"; } else { print LOOKUP "$prefix AS$origin : Error\n"; } # fflush (LOOKUP); } } sleep (3); } } sub whois_check { local ($prefix, $origin) = @_; local ($rr_prefix, $rr_origin) = (); local (@result); $origin = "AS" . $origin; # print "$prefix $origin\n"; @result = &whois ($prefix); foreach (@result) { if (/^route:.*\s([\d\.\/]+)$/) { $rr_prefix = $1; } if (/^origin:.*\s(AS[\d]+)$/) { $rr_origin = $1; if ($prefix eq $rr_prefix and $origin eq $rr_origin) { return 1; } } } alarm_mail ($prefix, $origin, @result); return 0; } ## get port of whois sub get_whois_port { local ($name, $aliases, $port, $proto) = getservbyname ("whois", "tcp"); return ($port, $proto); } ## whois lookup sub whois { local ($query) = @_; local ($port, $proto) = &get_whois_port; local (@result); if ($whois_host=~ /^\s*\d+\.\d+\.\d+\.\d+\s*$/) { $address = pack ("C4",split(/\./,$host)); } else { $address = (gethostbyname ($whois_host))[4]; } socket (SOCKET, PF_INET, SOCK_STREAM, $proto); if (connect (SOCKET, sockaddr_in ($port, $address))) { local ($oldhandle) = select (SOCKET); $| = 1; select($oldhandle); print SOCKET "$query\r\n"; @result = ; return @result; } } ## sub alarm_mail { local ($prefix, $origin, @result) = @_; open (MAIL, "|$mailer -t $mail_address") || die "can't open $mailer"; print MAIL "From: root\@rr1.jpix.ad.jp\n"; print MAIL "Subject: RR $origin $prefix\n"; print MAIL "MIME-Version: 1.0\n"; print MAIL "Content-Type: text/plain; charset=us-ascii \n\n"; print MAIL "RR Lookup Error Report\n"; print MAIL "======================\n"; print MAIL "Announced route : $prefix from $origin\n\n"; print MAIL "@result"; close MAIL; } quagga-0.99.22.4/tools/zc.pl0000755000175000017500000000533612177450262012356 00000000000000#!/usr/bin/env perl ## ## Zebra interactive console ## Copyright (C) 2000 Vladimir B. Grebenschikov ## ## This file is part of GNU Zebra. ## ## GNU Zebra is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by the ## Free Software Foundation; either version 2, or (at your option) any ## later version. ## ## GNU Zebra is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with GNU Zebra; see the file COPYING. If not, write to the ## Free Software Foundation, Inc., 59 Temple Place - Suite 330, ## Boston, MA 02111-1307, USA. use Net::Telnet (); use Getopt::Std; #use strict; my $host = `hostname -s`; $host =~ s/\s//g; my $port = 'zebra'; my $server = 'localhost'; # Check arguments &getopts ('l:e:czborh'); &usage () if $opt_h; # main { my $login_pass = $opt_l || $ENV{ZEBRA_PASSWORD} || 'zebra'; my $enable_pass = $opt_e || $ENV{ZEBRA_ENABLE} || ''; my $port = ($opt_z ? 'zebra' : 0) || ($opt_b ? 'bgpd' : 0) || ($opt_o ? 'ospfd' : 0) || ($opt_r ? 'ripd' : 0) || 'zebra'; my $cmd = join (' ', @ARGV); my $t = new Net::Telnet (Timeout => 10, Prompt => '/[\>\#] $/', Port => $port); $t->open ($server); $t->cmd ($login_pass); if ($enable_pass) { $t->cmd (String => 'en', Prompt => '/Password: /'); $t->cmd ($enable_pass); } $t->cmd ('conf t') if "$opt_c"; if ($cmd) { docmd ($t, $cmd); exit (0); } my $prompt = sprintf ("%s%s# ", $host, ($port eq 'zebra') ? '' : "/$port"); print "\nZEBRA interactive console ($port)\n\n" if -t STDIN; while (1) { $| = 1; print $prompt if -t STDIN; chomp ($cmd = <>); if (!defined ($cmd)) { print "\n" if -t STDIN; exit(0); } exit (0) if ($cmd eq 'q' || $cmd eq 'quit'); docmd ($t, $cmd) if $cmd !~ /^\s*$/; } exit(0); } sub docmd { my ($t, $cmd) = @_; my @lines = $t->cmd ($cmd); print join ('', grep (!/[\>\#] $/, @lines)), "\n"; } sub usage { print "USAGE: $0 [-l LOGIN_PASSWORD] [-e ENABLE_PASSWORD] [-z|-b|-o|-r|-h] []\n", "\t-l - specify login password\n", "\t-e - specify enable password\n", "\t-c - execute command in configure mode\n", "\t-z - connect to zebra daemon\n", "\t-b - connect to bgpd daemon\n", "\t-o - connect to ospfd daemon\n", "\t-r - connect to ripd daemon\n", "\t-h - help\n"; exit (1); } quagga-0.99.22.4/tools/zebra.el0000644000175000017500000000620012000052240012771 00000000000000;; -*- 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-0.99.22.4/update-autotools0000755000175000017500000000127112000052240013446 00000000000000#! /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-0.99.22.4/vtysh/0000755000175000017500000000000012211704577011470 500000000000000quagga-0.99.22.4/vtysh/Makefile.am0000644000175000017500000000264012177450262013446 00000000000000## Process this file with Automake to create Makefile.in INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" LIBS = @LIBS@ @CURSES@ @LIBPAM@ AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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)/babeld/*.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/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) ./$(EXTRA_DIST) $(vtysh_cmd_FILES) > vtysh_cmd.c quagga-0.99.22.4/vtysh/Makefile.in0000644000175000017500000005424212211704502013450 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/extract.pl.in $(top_srcdir)/depcomp 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) 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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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)/babeld/*.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/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 .PRECIOUS: 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) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool cscopelist ctags 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 uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-dist_examplesDATA vtysh_cmd.c: $(vtysh_cmd_FILES) ./$(EXTRA_DIST) $(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-0.99.22.4/vtysh/extract.pl0000755000175000017500000001347412211704554013426 00000000000000#! /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{'"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 babel"'} = "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"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; $ignore{'"key chain WORD"'} = "ignore"; $ignore{'"key <0-2147483647>"'} = "ignore"; $ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore"; $ignore{'"show route-map"'} = "ignore"; $ignore{'"line vty"'} = "ignore"; $ignore{'"who"'} = "ignore"; $ignore{'"terminal monitor"'} = "ignore"; $ignore{'"terminal no monitor"'} = "ignore"; $ignore{'"show history"'} = "ignore"; 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\/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 $cmd2str{$cmd} = $str; $cmd2defun{$cmd} = $defun_body; $cmd2proto{$cmd} = $protocol; } # install_element() process foreach (@install) { my (@element_array); @element_array = split (/,/); # Install node $enode = $element_array[0]; $enode =~ s/^\s+//g; $enode =~ s/\s+$//g; ($enode) = ($enode =~ /([0-9A-Z_]+)$/); # VTY command structure. ($ecmd) = ($element_array[1] =~ /&([^\)]+)/); $ecmd =~ s/^\s+//g; $ecmd =~ s/\s+$//g; # Register $ecmd if (defined ($cmd2str{$ecmd}) && ! defined ($ignore{$cmd2str{$ecmd}})) { my ($key); $key = $enode . "," . $cmd2str{$ecmd}; $ocmd{$key} = $ecmd; $odefun{$key} = $cmd2defun{$ecmd}; push (@{$oproto{$key}}, $cmd2proto{$ecmd}); } } } # Check finaly alive $cmd; foreach (keys %odefun) { my ($node, $str) = (split (/,/)); my ($cmd) = $ocmd{$_}; $live{$cmd} = $_; } # Output DEFSH foreach (keys %live) { my ($proto); my ($key); $key = $live{$_}; $proto = join ("|", @{$oproto{$key}}); printf "DEFSH ($proto$odefun{$key})\n\n"; } # Output install_element print < #include "command.h" #include "vtysh.h" EOF $ignore{'"interface IFNAME"'} = "ignore"; $ignore{'"ip vrf NAME"'} = "ignore"; $ignore{'"router rip"'} = "ignore"; $ignore{'"router ripng"'} = "ignore"; $ignore{'"router ospf"'} = "ignore"; $ignore{'"router ospf <0-65535>"'} = "ignore"; $ignore{'"router ospf6"'} = "ignore"; $ignore{'"router babel"'} = "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"'} = "ignore"; $ignore{'"address-family vpnv4"'} = "ignore"; $ignore{'"address-family vpnv4 unicast"'} = "ignore"; $ignore{'"address-family ipv4 vrf NAME"'} = "ignore"; $ignore{'"exit-address-family"'} = "ignore"; $ignore{'"key chain WORD"'} = "ignore"; $ignore{'"key <0-2147483647>"'} = "ignore"; $ignore{'"route-map WORD (deny|permit) <1-65535>"'} = "ignore"; $ignore{'"show route-map"'} = "ignore"; $ignore{'"line vty"'} = "ignore"; $ignore{'"who"'} = "ignore"; $ignore{'"terminal monitor"'} = "ignore"; $ignore{'"terminal no monitor"'} = "ignore"; $ignore{'"show history"'} = "ignore"; 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\/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 $cmd2str{$cmd} = $str; $cmd2defun{$cmd} = $defun_body; $cmd2proto{$cmd} = $protocol; } # install_element() process foreach (@install) { my (@element_array); @element_array = split (/,/); # Install node $enode = $element_array[0]; $enode =~ s/^\s+//g; $enode =~ s/\s+$//g; ($enode) = ($enode =~ /([0-9A-Z_]+)$/); # VTY command structure. ($ecmd) = ($element_array[1] =~ /&([^\)]+)/); $ecmd =~ s/^\s+//g; $ecmd =~ s/\s+$//g; # Register $ecmd if (defined ($cmd2str{$ecmd}) && ! defined ($ignore{$cmd2str{$ecmd}})) { my ($key); $key = $enode . "," . $cmd2str{$ecmd}; $ocmd{$key} = $ecmd; $odefun{$key} = $cmd2defun{$ecmd}; push (@{$oproto{$key}}, $cmd2proto{$ecmd}); } } } # Check finaly alive $cmd; foreach (keys %odefun) { my ($node, $str) = (split (/,/)); my ($cmd) = $ocmd{$_}; $live{$cmd} = $_; } # Output DEFSH foreach (keys %live) { my ($proto); my ($key); $key = $live{$_}; $proto = join ("|", @{$oproto{$key}}); printf "DEFSH ($proto$odefun{$key})\n\n"; } # Output install_element print < #include #include #include #include #include #include #include #include "command.h" #include "memory.h" #include "vtysh/vtysh.h" #include "log.h" #include "bgpd/bgp_vty.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 = "babeld", .flag = VTYSH_BABELD, .path = BABEL_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; } } /* Following filled with debug code to trace a problematic condition * under load - it SHOULD handle it. */ #define ERR_WHERE_STRING "vtysh(): vtysh_client_config(): " static int vtysh_client_config (struct vtysh_client *vclient, char *line) { int ret; char *buf; size_t bufsz; char *pbuf; size_t left; char *eoln; int nbytes; int i; int readln; if (vclient->fd < 0) return CMD_SUCCESS; ret = write (vclient->fd, line, strlen (line) + 1); if (ret <= 0) { vclient_close (vclient); return CMD_SUCCESS; } /* Allow enough room for buffer to read more than a few pages from socket. */ bufsz = 5 * 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"); return CMD_WARNING; } readln = (buf + bufsz) - pbuf - 1; nbytes = read (vclient->fd, pbuf, readln); if (nbytes <= 0) { if (errno == EINTR) continue; fprintf(stderr, ERR_WHERE_STRING "(%u)", errno); perror(""); if (errno == EAGAIN || errno == EIO) continue; vclient_close (vclient); XFREE(MTYPE_TMP, buf); return CMD_SUCCESS; } pbuf[nbytes] = '\0'; if (nbytes >= 4) { i = nbytes - 4; if (pbuf[i] == '\0' && pbuf[i + 1] == '\0' && pbuf[i + 2] == '\0') { ret = pbuf[i + 3]; break; } } pbuf += nbytes; /* See if a line exists in buffer, if so parse and consume it, and * reset read position. */ if ((eoln = strrchr(buf, '\n')) == NULL) continue; if (eoln >= ((buf + bufsz) - 1)) { fprintf (stderr, ERR_WHERE_STRING \ "warning - eoln beyond buffer end.\n"); } vtysh_config_parse(buf); eoln++; left = (size_t)(buf + bufsz - eoln); memmove(buf, eoln, left); buf[bufsz-1] = '\0'; pbuf = buf + strlen(buf); } /* Parse anything left in the buffer. */ vtysh_config_parse (buf); XFREE(MTYPE_TMP, buf); return ret; } static int vtysh_client_execute (struct vtysh_client *vclient, const char *line, FILE *fp) { int ret; char buf[1001]; int nbytes; int i; 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; } while (1) { nbytes = read (vclient->fd, buf, sizeof(buf)-1); if (nbytes <= 0 && errno != EINTR) { vclient_close (vclient); return CMD_SUCCESS; } if (nbytes > 0) { if ((numnulls == 3) && (nbytes == 1)) return buf[0]; buf[nbytes] = '\0'; fputs (buf, fp); fflush (fp); /* check for trailling \0\0\0, * even if split across reads * (see lib/vty.c::vtysh_read) */ if (nbytes >= 4) { i = nbytes-4; numnulls = 0; } else i = 0; while (i < nbytes && numnulls < 3) { if (buf[i++] == '\0') numnulls++; else numnulls = 0; } /* got 3 or more trailing NULs? */ if ((numnulls >= 3) && (i < nbytes)) return (buf[nbytes-1]); } } } void vtysh_exit_ripd_only (void) { if (ripd_client) vtysh_client_execute (ripd_client, "exit", stdout); } 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_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; vector vline; struct cmd_element *cmd; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { if (vty->buf[0] == '!' || vty->buf[1] == '#') continue; vline = cmd_make_strvec (vty->buf); /* In case of comment line. */ if (vline == NULL) continue; /* Execute configuration command : this is strict match. */ ret = cmd_execute_command_strict (vline, vty, &cmd); /* Try again with setting node to CONFIG_NODE. */ if (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING) { if (vty->node == KEYCHAIN_KEY_NODE) { vty->node = KEYCHAIN_NODE; vtysh_exit_ripd_only (); ret = cmd_execute_command_strict (vline, vty, &cmd); if (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING) { vtysh_exit_ripd_only (); vty->node = CONFIG_NODE; ret = cmd_execute_command_strict (vline, vty, &cmd); } } else { vtysh_execute ("end"); vtysh_execute ("configure terminal"); vty->node = CONFIG_NODE; ret = cmd_execute_command_strict (vline, vty, &cmd); } } cmd_free_strvec (vline); switch (ret) { case CMD_WARNING: if (vty->type == VTY_FILE) 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. */ int vtysh_rl_describe (void) { int ret; unsigned int i; vector vline; vector describe; int width; struct desc *desc; vline = cmd_make_strvec (rl_line_buffer); /* In case of '> ?'. */ if (vline == NULL) { vline = vector_init (1); vector_set (vline, '\0'); } else if (rl_end && isspace ((int) rl_line_buffer[rl_end - 1])) vector_set (vline, '\0'); describe = cmd_describe_command (vline, vty, &ret); 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 ((desc = vector_slot (describe, i)) != NULL) { int len; if (desc->cmd[0] == '\0') continue; len = strlen (desc->cmd); if (desc->cmd[0] == '.') len--; if (width < len) width = len; } for (i = 0; i < vector_active (describe); i++) if ((desc = vector_slot (describe, i)) != NULL) { if (desc->cmd[0] == '\0') continue; if (! desc->str) fprintf (stdout," %-s\n", desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd); else fprintf (stdout," %-*s %s\n", width, desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd, desc->str); } cmd_free_strvec (vline); vector_free (describe); rl_on_new_line(); return 0; } /* Result of cmd_complete_command() call will be stored here * and used in new_completion() in order to put the space in * correct places only. */ int complete_status; 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, '\0'); 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) rl_pending_input = ' '; } 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_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)# " }; /* Defined in lib/vty.c */ extern struct cmd_node vty_node; /* When '^Z' is received from vty, move down to the enable mode. */ 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_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_BABELD, router_babel, router_babel_cmd, "router babel", ROUTER_STR "Babel") { vty->node = BABEL_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_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; default: break; } return CMD_SUCCESS; } DEFUNSH (VTYSH_ALL, vtysh_exit_all, vtysh_exit_all_cmd, "exit", "Exit current mode and down to previous mode\n") { return vtysh_exit (vty); } ALIAS (vtysh_exit_all, vtysh_quit_all_cmd, "quit", "Exit current mode and down to previous mode\n") DEFUNSH (VTYSH_BGPD, exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_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; } /* TODO Implement "no interface command in isisd. */ DEFSH (VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D, vtysh_no_interface_cmd, "no interface IFNAME", NO_STR "Delete a pseudo interface's configuration\n" "Interface's name\n") /* 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") 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") /* 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; int ret; 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++) ret = vtysh_client_config (&vtysh_client[i], line); /* 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_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; int ret; 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++) ret = vtysh_client_config (&vtysh_client[i], line); 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") 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) { int ret; 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: ret = execlp (command, command, (const char *)NULL); break; case 1: ret = execlp (command, command, arg1, (const char *)NULL); break; case 2: ret = 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; ret = wait4 (pid, &status, 0, NULL); execute_flag = 0; } return 0; } DEFUN (vtysh_ping, vtysh_ping_cmd, "ping WORD", "Send echo messages\n" "Ping destination address or hostname\n") { execute_command ("ping", 1, argv[0], NULL); return CMD_SUCCESS; } 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 ('?', (Function *) vtysh_rl_describe); rl_completion_entry_function = vtysh_completion_entry_function; rl_attempted_completion_function = (CPPFunction *)new_completion; /* do not append space after completion. It will be appended * in new_completion() function explicitly. */ rl_completion_append_character = '\0'; } char * vtysh_prompt (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 (&rmap_node, NULL); install_node (&zebra_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); /* #ifdef HAVE_IPV6 */ install_node (&bgp_ipv6_node, NULL); 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 (RMAP_NODE); vtysh_install_default (ZEBRA_NODE); vtysh_install_default (BGP_VPNV4_NODE); vtysh_install_default (BGP_IPV4_NODE); vtysh_install_default (BGP_IPV4M_NODE); vtysh_install_default (BGP_IPV6_NODE); vtysh_install_default (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_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_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 (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_babel_cmd); 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_ipv4_unicast_cmd); install_element (BGP_NODE, &address_family_ipv4_multicast_cmd); #ifdef HAVE_IPV6 install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_unicast_cmd); #endif install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (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 (ENABLE_NODE, &vtysh_show_running_config_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); /* "write terminal" command. */ install_element (ENABLE_NODE, &vtysh_write_terminal_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); /* 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-0.99.22.4/vtysh/vtysh.conf.sample0000644000175000017500000000020012000052240014657 00000000000000! ! Sample configuration file for vtysh. ! !service integrated-vtysh-config !hostname quagga-router !username root nopassword ! quagga-0.99.22.4/vtysh/vtysh.h0000644000175000017500000000414412177450262012741 00000000000000/* 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_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD #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 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-0.99.22.4/vtysh/vtysh_config.c0000644000175000017500000002616512177450262014270 00000000000000/* 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; int line_cmp (char *c1, char *c2) { return strcmp (c1, c2); } void line_del (char *line) { XFREE (MTYPE_VTYSH_CONFIG_LINE, line); } struct config * config_new () { struct config *config; config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config)); return config; } int config_cmp (struct config *c1, struct config *c2) { return strcmp (c1->name, c2->name); } void config_del (struct config* config) { list_delete (config->line); if (config->name) XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name); XFREE (MTYPE_VTYSH_CONFIG, config); } struct config * config_get (int index, 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; } void config_add_line (struct list *config, const char *line) { listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line)); } 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)); } 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 ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0) config = config_get (BGP_IPV4M_NODE, line); else if (strncmp (line, " address-family ipv6", strlen (" address-family ipv6")) == 0) config = config_get (BGP_IPV6_NODE, line); else if (config->index == RMAP_NODE || config->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 babel", strlen ("router babel")) == 0) config = config_get (BABEL_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 occured 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-0.99.22.4/vtysh/vtysh_main.c0000644000175000017500000002246712132522417013741 00000000000000/* 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. */ void sigtstp (int sig) { /* Execute "end" command. */ vtysh_execute ("end"); /* Initialize readline. */ rl_initialize (); printf ("\n"); /* Check jmpflag for duplicate siglongjmp(). */ if (! jmpflag) return; jmpflag = 0; /* Back to main command loop. */ siglongjmp (jmpbuf, 1); } /* SIGINT handler. This function care user's ^Z input. */ void sigint (int sig) { /* Check this process is not child process. */ if (! execute_flag) { rl_initialize (); printf ("\n"); rl_forced_update_display (); } } /* Signale wrapper for vtysh. We don't use sigevent because * vtysh doesn't use threads. TODO */ RETSIGTYPE * vtysh_signal_set (int signo, void (*func)(int)) { int ret; struct sigaction sig; struct sigaction osig; sig.sa_handler = func; sigemptyset (&sig.sa_mask); sig.sa_flags = 0; #ifdef SA_RESTART sig.sa_flags |= SA_RESTART; #endif /* SA_RESTART */ ret = sigaction (signo, &sig, &osig); if (ret < 0) return (SIG_ERR); else return (osig.sa_handler); } /* Initialization of signal handles. */ void 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. */ 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); char *user = getenv("USER") ? : "boot"; char tod[64]; 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; /* 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(0, 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 (); sort_node (); /* 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); } /* 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'; 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; } 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); } } 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; snprintf(history_file, sizeof(history_file), "%s/.history_quagga", getenv("HOME")); read_history(history_file); /* 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-0.99.22.4/vtysh/vtysh_user.c0000644000175000017500000000735512132522417013772 00000000000000/* 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" #ifdef USE_PAM static struct pam_conv conv = { PAM_CONV_FUNC, NULL }; 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); /* 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; struct vtysh_user * user_new () { return XCALLOC (0, sizeof (struct vtysh_user)); } void user_free (struct vtysh_user *user) { XFREE (0, user); } 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; } 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); } } 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 () { struct vtysh_user *user; struct passwd *passwd; passwd = getpwuid (geteuid ()); user = user_lookup (passwd->pw_name); if (user && user->nopassword) /* Pass through */; else { #ifdef USE_PAM if (vtysh_pam (passwd->pw_name)) exit (0); #endif /* USE_PAM */ } return 0; } void vtysh_user_init () { userlist = list_new (); install_element (CONFIG_NODE, &username_nopassword_cmd); } quagga-0.99.22.4/vtysh/vtysh_user.h0000644000175000017500000000164212132522417013770 00000000000000/* User authentication for vtysh. * Copyright (C) 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _VTYSH_USER_H #define _VTYSH_USER_H int vtysh_auth (); #endif /* _VTYSH_USER_H */ quagga-0.99.22.4/watchquagga/0000755000175000017500000000000012211704577012607 500000000000000quagga-0.99.22.4/watchquagga/Makefile.am0000644000175000017500000000053612177450262014567 00000000000000## Process this file with Automake to create Makefile.in INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) sbin_PROGRAMS = watchquagga watchquagga_SOURCES = watchquagga.c watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@ quagga-0.99.22.4/watchquagga/Makefile.in0000644000175000017500000004453212211704502014570 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) 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 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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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 ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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 .PRECIOUS: 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) $(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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-sbinPROGRAMS cscopelist ctags 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 uninstall uninstall-am uninstall-sbinPROGRAMS # 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-0.99.22.4/watchquagga/watchquagga.c0000644000175000017500000011317712177450262015201 00000000000000/* 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\ 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\ ", 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], 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(const 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)); { const char *argv[4] = { "sh", "-c", shell_cmd, NULL}; execv("/bin/sh",(char *const *)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,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,delay.tv_sec,delay.tv_usec); } else zlog_warn("%s: slow echo response finally received after %ld.%06ld " "seconds", dmn->name,delay.tv_sec,delay.tv_usec); } else if (gs.loglevel > LOG_DEBUG+1) zlog_debug("%s: echo response received after %ld.%06ld seconds", dmn->name,delay.tv_sec,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]); } } { struct thread thread; while (thread_fetch (master, &thread)) thread_call (&thread); } /* Not reached. */ return 0; } quagga-0.99.22.4/zebra/0000755000175000017500000000000012211704576011415 500000000000000quagga-0.99.22.4/zebra/GNOME-PRODUCT-ZEBRA-MIB0000644000175000017500000000370012000052240014465 00000000000000GNOME-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-0.99.22.4/zebra/GNOME-SMI0000644000175000017500000000217312000052240012532 00000000000000GNOME-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-0.99.22.4/zebra/Makefile.am0000644000175000017500000000415412211105060013354 00000000000000## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 LIB_IPV6 = @LIB_IPV6@ LIBCAP = @LIBCAP@ ipforward = @IPFORWARD@ if_method = @IF_METHOD@ if_proc = @IF_PROC@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ other_method = @OTHER_METHOD@ ioctl_method = @IOCTL_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) $(if_proc) \ $(rt_method) $(rtread_method) $(kernel_method) $(other_method) if HAVE_NETLINK othersrc = zebra_fpm_netlink.c endif AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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 \ $(othersrc) 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 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 zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) zebra_DEPENDENCIES = $(otherobj) EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c if_proc.c \ if_sysctl.c ipforward_aix.c ipforward_ews.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ 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-0.99.22.4/zebra/Makefile.in0000644000175000017500000006274712211704502013407 00000000000000# Makefile.in generated by automake 1.12.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 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__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } 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 DIST_COMMON = $(dist_examples_DATA) $(noinst_HEADERS) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp 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) 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) testzebra_OBJECTS = $(am_testzebra_OBJECTS) am__DEPENDENCIES_1 = testzebra_DEPENDENCIES = ../lib/libzebra.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_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_fpm_netlink.c @HAVE_NETLINK_TRUE@am__objects_1 = zebra_fpm_netlink.$(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) $(am__objects_1) 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) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_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) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ 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) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ BUILD_TESTS = @BUILD_TESTS@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ 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@ IF_PROC = @IF_PROC@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib 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_IPV6 = @LIB_IPV6@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTHER_METHOD = @OTHER_METHOD@ 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@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ 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@ 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@ INSTALL_SDATA = @INSTALL@ -m 600 ipforward = @IPFORWARD@ if_method = @IF_METHOD@ if_proc = @IF_PROC@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ other_method = @OTHER_METHOD@ ioctl_method = @IOCTL_METHOD@ otherobj = $(ioctl_method) $(ipforward) $(if_method) $(if_proc) \ $(rt_method) $(rtread_method) $(kernel_method) $(other_method) @HAVE_NETLINK_TRUE@othersrc = zebra_fpm_netlink.c AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) 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 \ $(othersrc) 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 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 zebra_LDADD = $(otherobj) ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) testzebra_LDADD = ../lib/libzebra.la $(LIBCAP) $(LIB_IPV6) zebra_DEPENDENCIES = $(otherobj) EXTRA_DIST = if_ioctl.c if_ioctl_solaris.c if_netlink.c if_proc.c \ if_sysctl.c ipforward_aix.c ipforward_ews.c ipforward_proc.c \ ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ 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 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 zebra/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu zebra/Makefile .PRECIOUS: 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-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) $(LINK) $(testzebra_OBJECTS) $(testzebra_LDADD) $(LIBS) zebra$(EXEEXT): $(zebra_OBJECTS) $(zebra_DEPENDENCIES) $(EXTRA_zebra_DEPENDENCIES) @rm -f zebra$(EXEEXT) $(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_netlink.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zebra_rib.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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(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: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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 CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ 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: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ 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 all all-am check check-am clean clean-generic \ clean-libtool clean-noinstPROGRAMS clean-sbinPROGRAMS \ cscopelist ctags 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 uninstall uninstall-am uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS # 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-0.99.22.4/zebra/connected.c0000644000175000017500000002645112177450262013454 00000000000000/* * 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; /* withdraw 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_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); } 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; listnode_add (ifp->connected, ifc); /* Update interface address information to protocol daemon. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) { if (ifc->address->family == AF_INET) if_subnet_add (ifp, ifc); SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); 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 */ 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; return 1; } /* Handle implicit withdrawals of addresses, where a system ADDs an address * to an interface which already has the same address configured. * * Returns the struct connected which must be announced to clients, * or NULL if nothing to do. */ static struct connected * connected_implicit_withdraw (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) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL)) { /* nothing to do */ connected_free (ifc); return NULL; } UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED); connected_withdraw (current); /* implicit withdraw - freebsd does this */ } return 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, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST); rib_update (); } /* 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; /* 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); /* nothing to do? */ if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) return; connected_announce (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, 0, SAFI_UNICAST); rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_MULTICAST); rib_update (); } /* 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(); } #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); #if ! defined (MUSICA) && ! defined (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, RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST); rib_update (); } /* 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; /* 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); if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) return; connected_announce (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, 0, SAFI_UNICAST); rib_update (); } 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(); } #endif /* HAVE_IPV6 */ quagga-0.99.22.4/zebra/connected.h0000644000175000017500000000365012132522417013446 00000000000000/* * 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-0.99.22.4/zebra/debug.c0000644000175000017500000002454712177450262012604 00000000000000/* * 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; DEFUN (show_debugging_zebra, show_debugging_zebra_cmd, "show debugging zebra", SHOW_STR "Zebra configuration\n" "Debugging information\n") { vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE); if (IS_ZEBRA_DEBUG_EVENT) vty_out (vty, " Zebra event debugging is on%s", VTY_NEWLINE); if (IS_ZEBRA_DEBUG_PACKET) { if (IS_ZEBRA_DEBUG_SEND && IS_ZEBRA_DEBUG_RECV) { vty_out (vty, " Zebra packet%s debugging is on%s", IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", VTY_NEWLINE); } else { if (IS_ZEBRA_DEBUG_SEND) vty_out (vty, " Zebra packet send%s debugging is on%s", IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", VTY_NEWLINE); else vty_out (vty, " Zebra packet receive%s debugging is on%s", IS_ZEBRA_DEBUG_DETAIL ? " detail" : "", VTY_NEWLINE); } } if (IS_ZEBRA_DEBUG_KERNEL) vty_out (vty, " Zebra kernel debugging is on%s", VTY_NEWLINE); 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); return CMD_SUCCESS; } DEFUN (debug_zebra_events, debug_zebra_events_cmd, "debug zebra events", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra events\n") { zebra_debug_event = ZEBRA_DEBUG_EVENT; return CMD_WARNING; } DEFUN (debug_zebra_packet, debug_zebra_packet_cmd, "debug zebra packet", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra packet\n") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; zebra_debug_packet |= ZEBRA_DEBUG_SEND; zebra_debug_packet |= ZEBRA_DEBUG_RECV; return CMD_SUCCESS; } DEFUN (debug_zebra_packet_direct, debug_zebra_packet_direct_cmd, "debug zebra packet (recv|send)", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) zebra_debug_packet |= ZEBRA_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) zebra_debug_packet |= ZEBRA_DEBUG_RECV; zebra_debug_packet &= ~ZEBRA_DEBUG_DETAIL; return CMD_SUCCESS; } DEFUN (debug_zebra_packet_detail, debug_zebra_packet_detail_cmd, "debug zebra packet (recv|send) detail", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n" "Debug option set detaied information\n") { zebra_debug_packet = ZEBRA_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) zebra_debug_packet |= ZEBRA_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) zebra_debug_packet |= ZEBRA_DEBUG_RECV; zebra_debug_packet |= ZEBRA_DEBUG_DETAIL; return CMD_SUCCESS; } DEFUN (debug_zebra_kernel, debug_zebra_kernel_cmd, "debug zebra kernel", DEBUG_STR "Zebra configuration\n" "Debug option set for zebra between kernel interface\n") { zebra_debug_kernel = ZEBRA_DEBUG_KERNEL; return CMD_SUCCESS; } DEFUN (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_packet, no_debug_zebra_packet_cmd, "no debug zebra packet", NO_STR DEBUG_STR "Zebra configuration\n" "Debug option set for zebra packet\n") { zebra_debug_packet = 0; return CMD_SUCCESS; } DEFUN (no_debug_zebra_packet_direct, no_debug_zebra_packet_direct_cmd, "no debug zebra packet (recv|send)", NO_STR DEBUG_STR "Zebra configuration\n" "Debug option set for zebra packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") { if (strncmp ("send", argv[0], strlen (argv[0])) == 0) zebra_debug_packet &= ~ZEBRA_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) zebra_debug_packet &= ~ZEBRA_DEBUG_RECV; return CMD_SUCCESS; } DEFUN (no_debug_zebra_kernel, no_debug_zebra_kernel_cmd, "no debug zebra kernel", NO_STR DEBUG_STR "Zebra configuration\n" "Debug option set for zebra between kernel interface\n") { zebra_debug_kernel = 0; return CMD_SUCCESS; } 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, &show_debugging_zebra_cmd); install_element (ENABLE_NODE, &debug_zebra_events_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd); install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd); install_element (ENABLE_NODE, &debug_zebra_kernel_cmd); install_element (ENABLE_NODE, &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_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_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_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-0.99.22.4/zebra/debug.h0000644000175000017500000000411712177450262012600 00000000000000/* * 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 /* 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) 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 void zebra_debug_init (void); #endif /* _ZEBRA_DEBUG_H */ quagga-0.99.22.4/zebra/if_ioctl.c0000644000175000017500000002656412132522417013300 00000000000000/* * Interface looking up by ioctl (). * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "sockunion.h" #include "prefix.h" #include "ioctl.h" #include "connected.h" #include "memory.h" #include "log.h" #include "zebra/interface.h" /* Interface looking up using infamous SIOCGIFCONF. */ 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 () { /* 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-0.99.22.4/zebra/if_ioctl_solaris.c0000644000175000017500000002416612132522417015030 00000000000000/* * 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 "zebra/interface.h" void lifreq_set_name (struct lifreq *, const char *); int if_get_flags_direct (const char *, uint64_t *, unsigned int af); 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; 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. */ 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 () { 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-0.99.22.4/zebra/if_netlink.c0000644000175000017500000000202312132522417013612 00000000000000/* * 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" extern int interface_lookup_netlink (void); /* Interface information read by netlink. */ void interface_list (void) { interface_lookup_netlink (); } quagga-0.99.22.4/zebra/if_proc.c0000644000175000017500000001413112132522417013114 00000000000000/* Interface name and statistics get function using proc file system * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "log.h" #include "zebra/ioctl.h" #include "zebra/connected.h" #include "zebra/interface.h" /* Proc filesystem one line buffer. */ #define PROCBUFSIZ 1024 /* Path to device proc file system. */ #ifndef _PATH_PROC_NET_DEV #define _PATH_PROC_NET_DEV "/proc/net/dev" #endif /* _PATH_PROC_NET_DEV */ /* Return statistics data pointer. */ static char * interface_name_cut (char *buf, char **name) { char *stat; /* Skip white space. Line will include header spaces. */ while (*buf == ' ') buf++; *name = buf; /* Cut interface name. */ stat = strrchr (buf, ':'); *stat++ = '\0'; return stat; } /* Fetch each statistics field. */ static int ifstat_dev_fields (int version, char *buf, struct interface *ifp) { switch (version) { case 3: sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", &ifp->stats.rx_bytes, &ifp->stats.rx_packets, &ifp->stats.rx_errors, &ifp->stats.rx_dropped, &ifp->stats.rx_fifo_errors, &ifp->stats.rx_frame_errors, &ifp->stats.rx_compressed, &ifp->stats.rx_multicast, &ifp->stats.tx_bytes, &ifp->stats.tx_packets, &ifp->stats.tx_errors, &ifp->stats.tx_dropped, &ifp->stats.tx_fifo_errors, &ifp->stats.collisions, &ifp->stats.tx_carrier_errors, &ifp->stats.tx_compressed); break; case 2: sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", &ifp->stats.rx_bytes, &ifp->stats.rx_packets, &ifp->stats.rx_errors, &ifp->stats.rx_dropped, &ifp->stats.rx_fifo_errors, &ifp->stats.rx_frame_errors, &ifp->stats.tx_bytes, &ifp->stats.tx_packets, &ifp->stats.tx_errors, &ifp->stats.tx_dropped, &ifp->stats.tx_fifo_errors, &ifp->stats.collisions, &ifp->stats.tx_carrier_errors); ifp->stats.rx_multicast = 0; break; case 1: sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", &ifp->stats.rx_packets, &ifp->stats.rx_errors, &ifp->stats.rx_dropped, &ifp->stats.rx_fifo_errors, &ifp->stats.rx_frame_errors, &ifp->stats.tx_packets, &ifp->stats.tx_errors, &ifp->stats.tx_dropped, &ifp->stats.tx_fifo_errors, &ifp->stats.collisions, &ifp->stats.tx_carrier_errors); ifp->stats.rx_bytes = 0; ifp->stats.tx_bytes = 0; ifp->stats.rx_multicast = 0; break; } return 0; } /* Update interface's statistics. */ void ifstat_update_proc (void) { FILE *fp; char buf[PROCBUFSIZ]; int version; struct interface *ifp; char *stat; char *name; /* Open /proc/net/dev. */ fp = fopen (_PATH_PROC_NET_DEV, "r"); if (fp == NULL) { zlog_warn ("Can't open proc file %s: %s", _PATH_PROC_NET_DEV, safe_strerror (errno)); return; } /* Drop header lines. */ fgets (buf, PROCBUFSIZ, fp); fgets (buf, PROCBUFSIZ, fp); /* To detect proc format veresion, parse second line. */ if (strstr (buf, "compressed")) version = 3; else if (strstr (buf, "bytes")) version = 2; else version = 1; /* Update each interface's statistics. */ while (fgets (buf, PROCBUFSIZ, fp) != NULL) { stat = interface_name_cut (buf, &name); ifp = if_get_by_name (name); ifstat_dev_fields (version, stat, ifp); } fclose(fp); return; } /* Interface structure allocation by proc filesystem. */ int interface_list_proc () { FILE *fp; char buf[PROCBUFSIZ]; struct interface *ifp; char *name; /* Open /proc/net/dev. */ fp = fopen (_PATH_PROC_NET_DEV, "r"); if (fp == NULL) { zlog_warn ("Can't open proc file %s: %s", _PATH_PROC_NET_DEV, safe_strerror (errno)); return -1; } /* Drop header lines. */ fgets (buf, PROCBUFSIZ, fp); fgets (buf, PROCBUFSIZ, fp); /* Only allocate interface structure. Other jobs will be done in if_ioctl.c. */ while (fgets (buf, PROCBUFSIZ, fp) != NULL) { interface_name_cut (buf, &name); ifp = if_get_by_name (name); if_add_update (ifp); } fclose(fp); return 0; } #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) #ifndef _PATH_PROC_NET_IF_INET6 #define _PATH_PROC_NET_IF_INET6 "/proc/net/if_inet6" #endif /* _PATH_PROC_NET_IF_INET6 */ int ifaddr_proc_ipv6 () { FILE *fp; char buf[PROCBUFSIZ]; int n; char addr[33]; char ifname[21]; int ifindex, plen, scope, status; struct interface *ifp; struct prefix_ipv6 p; /* Open proc file system. */ fp = fopen (_PATH_PROC_NET_IF_INET6, "r"); if (fp == NULL) { zlog_warn ("Can't open proc file %s: %s", _PATH_PROC_NET_IF_INET6, safe_strerror (errno)); return -1; } /* Get interface's IPv6 address. */ while (fgets (buf, PROCBUFSIZ, fp) != NULL) { n = sscanf (buf, "%32s %02x %02x %02x %02x %20s", addr, &ifindex, &plen, &scope, &status, ifname); if (n != 6) continue; ifp = if_get_by_name (ifname); /* Fetch interface's IPv6 address. */ str2in6_addr (addr, &p.prefix); p.prefixlen = plen; connected_add_ipv6 (ifp, 0, &p.prefix, p.prefixlen, NULL, ifname); } fclose (fp); return 0; } #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ quagga-0.99.22.4/zebra/if_sysctl.c0000644000175000017500000000666712132522417013511 00000000000000/* * 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 "zebra/rt.h" #include "zebra/kernel_socket.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 () { 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 }; /* 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-0.99.22.4/zebra/interface.c0000644000175000017500000012600012177450262013441 00000000000000/* * Interface function. * Copyright (C) 1997, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "vty.h" #include "sockunion.h" #include "prefix.h" #include "command.h" #include "memory.h" #include "ioctl.h" #include "connected.h" #include "log.h" #include "zclient.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/irdp.h" #ifdef 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 /* RTADV */ /* 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_UNSPEC; #ifdef RTADV { /* Set default router advertise values. */ struct rtadvconf *rtadv; rtadv = &zebra_if->rtadv; rtadv->AdvSendAdvertisements = 0; rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; rtadv->AdvIntervalTimer = 0; rtadv->AdvManagedFlag = 0; rtadv->AdvOtherConfigFlag = 0; rtadv->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 /* 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)) return -1; route_unlock_node (rn); /* Untie address from subnet's address list. */ addr_list = rn->info; 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 (listhead (addr_list)); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY); 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_REAL)) { /* Address check. */ if (p->family == AF_INET) { if (! if_is_up (ifp)) { /* XXX: WTF is it trying to set flags here? * caller has just gotten a new interface, has been * handed the flags already. This code has no business * trying to override administrative status of the interface. * The only call path to here which doesn't originate from * kernel event is irdp - what on earth is it trying to do? * * further 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; } /* Add to subnet chain list. */ if_subnet_add (ifp, ifc); SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); zebra_interface_address_add_update (ifp, ifc); if (if_is_operative(ifp)) connected_up_ipv4 (ifp, ifc); } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { if (! if_is_up (ifp)) { /* XXX: 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_REAL); zebra_interface_address_add_update (ifp, ifc); if (if_is_operative(ifp)) connected_up_ipv6 (ifp, ifc); } #endif /* HAVE_IPV6 */ } } } /* Handle interface addition */ void if_add_update (struct interface *ifp) { struct zebra_if *if_data; if_data = ifp->info; 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_addr_wakeup (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s index %d becomes active.", ifp->name, ifp->ifindex); } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s index %d is added.", ifp->name, ifp->ifindex); } } /* 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 index %d is still up while being deleted.", ifp->name, ifp->ifindex); return; } /* Mark interface as inactive */ UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("interface %s index %d is now inactive.", ifp->name, 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); zebra_interface_address_delete_update (ifp, ifc); UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* 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); 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; /* 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 (); } /* 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; /* 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 (); } 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 (connected->label) vty_out (vty, " %s", connected->label); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef 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 /* RTADV */ /* Interface's information print out to vty interface. */ static void if_dump_vty (struct vty *vty, struct interface *ifp) { #ifdef HAVE_STRUCT_SOCKADDR_DL struct sockaddr_dl *sdl; #endif /* HAVE_STRUCT_SOCKADDR_DL */ 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); } 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. */ #ifdef HAVE_STRUCT_SOCKADDR_DL sdl = &ifp->sdl; if (sdl != NULL && sdl->sdl_alen != 0) { int i; u_char *ptr; vty_out (vty, " HWaddr: "); for (i = 0, ptr = (u_char *)LLADDR (sdl); i < sdl->sdl_alen; i++, ptr++) vty_out (vty, "%s%02x", i == 0 ? "" : ":", *ptr); vty_out (vty, "%s", VTY_NEWLINE); } #else if (ifp->hw_addr_len != 0) { int i; vty_out (vty, " HWaddr: "); for (i = 0; i < ifp->hw_addr_len; i++) vty_out (vty, "%s%02x", i == 0 ? "" : ":", ifp->hw_addr[i]); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_STRUCT_SOCKADDR_DL */ /* 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); } #ifdef RTADV nd_dump_vty (vty, ifp); #endif /* 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 %qu, bytes %qu, dropped %qu," " multicast packets %qu%s", ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, VTY_NEWLINE); vty_out (vty, " input errors %qu%s", ifp->stats.ifi_ierrors, VTY_NEWLINE); vty_out (vty, " output packets %qu, bytes %qu, multicast packets %qu%s", ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, ifp->stats.ifi_omcasts, VTY_NEWLINE); vty_out (vty, " output errors %qu%s", ifp->stats.ifi_oerrors, VTY_NEWLINE); vty_out (vty, " collisions %qu%s", ifp->stats.ifi_collisions, VTY_NEWLINE); #else /* Statistics print out using sysctl (). */ vty_out (vty, " input packets %lu, bytes %lu, dropped %lu," " multicast packets %lu%s", ifp->stats.ifi_ipackets, ifp->stats.ifi_ibytes, ifp->stats.ifi_iqdrops, ifp->stats.ifi_imcasts, VTY_NEWLINE); vty_out (vty, " input errors %lu%s", ifp->stats.ifi_ierrors, VTY_NEWLINE); vty_out (vty, " output packets %lu, bytes %lu, multicast packets %lu%s", ifp->stats.ifi_opackets, ifp->stats.ifi_obytes, ifp->stats.ifi_omcasts, VTY_NEWLINE); vty_out (vty, " output errors %lu%s", ifp->stats.ifi_oerrors, VTY_NEWLINE); vty_out (vty, " collisions %lu%s", ifp->stats.ifi_collisions, VTY_NEWLINE); #endif /* __bsdi__ || __NetBSD__ */ #endif /* HAVE_NET_RT_IFLIST */ } /* 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; } struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 }; /* Show all or specified interface to vty. */ DEFUN (show_interface, show_interface_cmd, "show interface [IFNAME]", SHOW_STR "Interface status and configuration\n" "Inteface name\n") { struct listnode *node; struct interface *ifp; #ifdef HAVE_PROC_NET_DEV /* If system has interface statistics via proc file system, update statistics. */ ifstat_update_proc (); #endif /* HAVE_PROC_NET_DEV */ #ifdef HAVE_NET_RT_IFLIST ifstat_update_sysctl (); #endif /* HAVE_NET_RT_IFLIST */ /* Specified interface print. */ if (argc != 0) { ifp = if_lookup_by_name (argv[0]); if (ifp == NULL) { vty_out (vty, "%% Can't find interface %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } if_dump_vty (vty, ifp); return CMD_SUCCESS; } /* All interface print. */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) if_dump_vty (vty, ifp); return CMD_SUCCESS; } DEFUN (show_interface_desc, show_interface_desc_cmd, "show interface description", SHOW_STR "Interface status and configuration\n" "Interface description\n") { struct listnode *node; struct interface *ifp; vty_out (vty, "Interface Status Protocol Description%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (iflist, 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); } 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; } DEFUN (linkdetect, linkdetect_cmd, "link-detect", "Enable link detection on interface\n") { struct interface *ifp; int if_was_operative; ifp = (struct interface *) vty->index; if_was_operative = if_is_operative(ifp); SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); /* When linkdetection is enabled, if might come down */ if (!if_is_operative(ifp) && if_was_operative) if_down(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; int if_was_operative; ifp = (struct interface *) vty->index; if_was_operative = if_is_operative(ifp); UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); /* Interface may come up after disabling link detection */ if (if_is_operative(ifp) && !if_was_operative) if_up(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; ret = if_unset_flags (ifp, IFF_UP); if (ret < 0) { vty_out (vty, "Can't shutdown interface%s", VTY_NEWLINE); return CMD_WARNING; } if_refresh (ifp); if_data = ifp->info; if_data->shutdown = IF_ZEBRA_SHUTDOWN_ON; return CMD_SUCCESS; } DEFUN (no_shutdown_if, no_shutdown_if_cmd, "no shutdown", NO_STR "Shutdown the selected interface\n") { int ret; struct interface *ifp; struct zebra_if *if_data; ifp = (struct interface *) vty->index; ret = if_set_flags (ifp, IFF_UP | IFF_RUNNING); if (ret < 0) { vty_out (vty, "Can't up interface%s", VTY_NEWLINE); return CMD_WARNING; } if_refresh (ifp); if_data = ifp->info; if_data->shutdown = IF_ZEBRA_SHUTDOWN_OFF; return CMD_SUCCESS; } DEFUN (bandwidth_if, bandwidth_if_cmd, "bandwidth <1-10000000>", "Set bandwidth informational parameter\n" "Bandwidth in kilobits\n") { struct interface *ifp; unsigned int bandwidth; ifp = (struct interface *) vty->index; bandwidth = strtol(argv[0], NULL, 10); /* bandwidth range is <1-10000000> */ if (bandwidth < 1 || bandwidth > 10000000) { vty_out (vty, "Bandwidth is invalid%s", VTY_NEWLINE); return CMD_WARNING; } ifp->bandwidth = bandwidth; /* force protocols to recalculate routes due to cost change */ if (if_is_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") static int ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label) { struct prefix_ipv4 cp; struct connected *ifc; struct prefix_ipv4 *p; int ret; ret = str2prefix_ipv4 (addr_str, &cp); if (ret <= 0) { vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); return CMD_WARNING; } ifc = connected_check (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_REAL) && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { /* Some system need to up the interface to set IP address. */ if (! if_is_up (ifp)) { if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } ret = if_set_prefix (ifp, ifc); if (ret < 0) { vty_out (vty, "%% Can't set interface IP address: %s.%s", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Add to subnet chain list (while marking secondary attribute). */ if_subnet_add (ifp, ifc); /* IP address propery set. */ SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* Update interface address information to protocol daemon. */ zebra_interface_address_add_update (ifp, ifc); /* If interface is up register connected route. */ if (if_is_operative(ifp)) connected_up_ipv4 (ifp, ifc); } 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_REAL) || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { listnode_delete (ifp->connected, ifc); connected_free (ifc); return CMD_WARNING; } /* This is real route. */ ret = if_unset_prefix (ifp, ifc); if (ret < 0) { vty_out (vty, "%% Can't unset interface IP address: %s.%s", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* success! call returned that the address deletion went through. * this is a synchronous operation, so we know it succeeded and can * now update all internal state. */ /* the HAVE_NETLINK check is only here because, on BSD, although the * call above is still synchronous, we get a second confirmation later * through the route socket, and we don't want to touch that behaviour * for now. It should work without the #ifdef, but why take the risk... * -- equinox 2012-07-13 */ #ifdef HAVE_NETLINK /* Remove connected route. */ connected_down_ipv4 (ifp, ifc); /* Redistribute this information. */ zebra_interface_address_delete_update (ifp, ifc); /* IP address propery set. */ UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* remove from interface, remark secondaries */ if_subnet_delete (ifp, ifc); /* Free address information. */ listnode_delete (ifp->connected, ifc); connected_free (ifc); #endif 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 prefix_ipv6 cp; struct connected *ifc; struct prefix_ipv6 *p; int ret; ret = str2prefix_ipv6 (addr_str, &cp); if (ret <= 0) { vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); return CMD_WARNING; } ifc = connected_check (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_REAL) && CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { /* Some system need to up the interface to set IP address. */ if (! if_is_up (ifp)) { if_set_flags (ifp, IFF_UP | IFF_RUNNING); if_refresh (ifp); } ret = if_prefix_add_ipv6 (ifp, ifc); if (ret < 0) { vty_out (vty, "%% Can't set interface IP address: %s.%s", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* IP address propery set. */ SET_FLAG (ifc->conf, ZEBRA_IFC_REAL); /* Update interface address information to protocol daemon. */ zebra_interface_address_add_update (ifp, ifc); /* If interface is up register connected route. */ if (if_is_operative(ifp)) connected_up_ipv6 (ifp, ifc); } 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; /* This is not real address or interface is not active. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { listnode_delete (ifp->connected, ifc); connected_free (ifc); return CMD_WARNING; } /* This is real route. */ ret = if_prefix_delete_ipv6 (ifp, ifc); if (ret < 0) { vty_out (vty, "%% Can't unset interface IP address: %s.%s", safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Redistribute this information. */ zebra_interface_address_delete_update (ifp, ifc); /* Remove connected route. */ connected_down_ipv6 (ifp, ifc); /* Free address information. */ listnode_delete (ifp->connected, ifc); connected_free (ifc); return CMD_SUCCESS; } DEFUN (ipv6_address, ipv6_address_cmd, "ipv6 address X:X::X:X/M", "Interface 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 if_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct zebra_if *if_data; struct listnode *addrnode; struct connected *ifc; struct prefix *p; if_data = ifp->info; vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); /* Assign bandwidth here to avoid unnecessary interface flap while processing config script */ if (ifp->bandwidth != 0) vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) vty_out(vty, " link-detect%s", VTY_NEWLINE); 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/%d", p->family == AF_INET ? "" : "v6", inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf)), p->prefixlen); if (ifc->label) vty_out (vty, " label %s", ifc->label); vty_out (vty, "%s", VTY_NEWLINE); } } if (if_data) { if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) vty_out (vty, " shutdown%s", VTY_NEWLINE); if (if_data->multicast != IF_ZEBRA_MULTICAST_UNSPEC) vty_out (vty, " %smulticast%s", if_data->multicast == IF_ZEBRA_MULTICAST_ON ? "" : "no ", VTY_NEWLINE); } #ifdef RTADV rtadv_config_write (vty, ifp); #endif /* RTADV */ #ifdef HAVE_IRDP irdp_config_write (vty, ifp); #endif /* IRDP */ vty_out (vty, "!%s", VTY_NEWLINE); } return 0; } /* Allocate and initialize interface vector. */ void zebra_if_init (void) { /* Initialize interface and new hook. */ if_init (); if_add_hook (IF_NEW_HOOK, if_zebra_new_hook); if_add_hook (IF_DELETE_HOOK, if_zebra_delete_hook); /* Install configuration write function. */ install_node (&interface_node, if_config_write); install_element (VIEW_NODE, &show_interface_cmd); install_element (ENABLE_NODE, &show_interface_cmd); install_element (ENABLE_NODE, &show_interface_desc_cmd); install_element (CONFIG_NODE, &zebra_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 (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 */ } quagga-0.99.22.4/zebra/interface.h0000644000175000017500000001677212132522417013455 00000000000000/* 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" #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_UNSPEC 0 #define IF_ZEBRA_SHUTDOWN_ON 1 #define IF_ZEBRA_SHUTDOWN_OFF 2 /* Router advertisement feature. */ #if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME) #ifdef HAVE_RTADV #define RTADV #endif #endif #ifdef 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 /* 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; /* Installed addresses chains tree. */ struct route_table *ipv4_subnets; #ifdef RTADV struct rtadvconf rtadv; #endif /* RTADV */ #ifdef HAVE_IRDP struct irdp_interface irdp; #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 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 */ #ifdef BSDI extern int if_kvm_get_mtu (struct interface *); #endif /* BSDI */ #endif /* _ZEBRA_INTERFACE_H */ quagga-0.99.22.4/zebra/ioctl.c0000644000175000017500000003532412132522417012614 00000000000000/* * 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; 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; 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; rib_lookup_and_pushup (p); 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-0.99.22.4/zebra/ioctl.h0000644000175000017500000000374112132522417012617 00000000000000/* * 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-0.99.22.4/zebra/ioctl_null.c0000644000175000017500000000314212177450262013646 00000000000000#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-0.99.22.4/zebra/ioctl_solaris.c0000644000175000017500000002324112132522417014343 00000000000000/* * 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 "zebra/rib.h" #include "zebra/rt.h" #include "zebra/interface.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, ret6; 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[INET_ADDRSTRLEN]; inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix), addrbuf, sizeof (addrbuf)); zlog_warn ("Can't set %s on interface %s", addrbuf, ifp->name); return 0; } int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { char addrbuf[INET_ADDRSTRLEN]; inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix), addrbuf, sizeof (addrbuf)); zlog_warn ("Can't delete %s on interface %s", addrbuf, ifp->name); return 0; } #endif /* HAVE_IPV6 */ quagga-0.99.22.4/zebra/ipforward.h0000644000175000017500000000221212132522417013472 00000000000000/* 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-0.99.22.4/zebra/ipforward_aix.c0000644000175000017500000000250312132522417014331 00000000000000/* * ipforward value get function for aix. * Copyright (C) 1997 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include int ipforward () { int fd, ret; int af = AF_INET; char netopt[] = "ipforwarding"; struct optreq oq; fd = socket(af, SOCK_DGRAM, 0); if (fd < 0) { /* need logging here */ return -1; } strcpy (oq.name, netopt); oq.getnext = 0; ret = ioctl (fd, SIOCGNETOPT, (caddr_t)&oq); close(fd); if (ret < 0) { /* need logging here */ return -1; } ret = atoi (oq.data); return ret; } int ipforward_on () { ; } int ipforward_off () { ; } quagga-0.99.22.4/zebra/ipforward_ews.c0000644000175000017500000000246112132522417014351 00000000000000/* * Ipforward value get function for NEC EWS. * Copyright (C) 1997 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include int ipforward () { int fd; char buf[BUFSIZ]; struct mioc_rksym rks; fd = open ("/dev/kmem", O_RDWR); if (fd < 0) { /* need logging here */ return -1; } rks.mirk_symname = "ipforwarding"; rks.mirk_buf = buf; rks.mirk_buflen = sizeof (int); if (ioctl (fd, MIOC_READKSYM, &rks) < 0) { /* need logging here */ return -1; } close (fd); return *(int *)buf; } int ipforward_on () { ; } int ipforward_off () { ; } quagga-0.99.22.4/zebra/ipforward_proc.c0000644000175000017500000001016212132522417014513 00000000000000/* * 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-0.99.22.4/zebra/ipforward_solaris.c0000644000175000017500000001042712132522417015230 00000000000000/* * 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-0.99.22.4/zebra/ipforward_sysctl.c0000644000175000017500000001065212132522417015075 00000000000000/* 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" #ifdef NRL #include #endif /* NRL */ #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) || (defined(__bsdi__) && _BSDI_VERSION >= 199802 ) || defined(NRL) 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-0.99.22.4/zebra/irdp.h0000644000175000017500000001152712132522417012444 00000000000000/* 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-0.99.22.4/zebra/irdp_interface.c0000644000175000017500000004267612132522417014470 00000000000000/* * * 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 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 (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-0.99.22.4/zebra/irdp_main.c0000644000175000017500000001745412132522417013450 00000000000000/* * * 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; 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/%d Holdtime=%d Preference=%d", ifp->name, inet_ntoa(p->u.prefix4), p->prefixlen, irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime, get_pref(irdp, p)); send_packet (ifp, s, dst, p, ttl); } 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-0.99.22.4/zebra/irdp_packet.c0000644000175000017500000002120412132522417013757 00000000000000/* * * 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 doesnt 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 doesnt 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-0.99.22.4/zebra/kernel_netlink.c0000644000175000017500000000152412132522417014501 00000000000000/* 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-0.99.22.4/zebra/kernel_null.c0000644000175000017500000000323312177450262014015 00000000000000/* NULL kernel methods for testing. */ #include #include #include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/redistribute.h" #include "zebra/connected.h" int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak kernel_delete_ipv4 = kernel_add_ipv4 #else int kernel_delete_ipv4 (struct prefix *a, struct rib *b) { return 0; } #endif int kernel_add_ipv6 (struct prefix *a, struct rib *b) { return 0; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak kernel_delete_ipv6 = kernel_add_ipv6 #else int kernel_delete_ipv6 (struct prefix *a, struct rib *b) { return 0; } #endif int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table) { 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 (void) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak route_read = kernel_init #else void route_read (void) { return; } #endif quagga-0.99.22.4/zebra/kernel_socket.c0000644000175000017500000011402712177450262014337 00000000000000/* Kernel communication using routing socket. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "sockunion.h" #include "connected.h" #include "memory.h" #include "ioctl.h" #include "log.h" #include "str.h" #include "table.h" #include "rib.h" #include "privs.h" #include "zebra/interface.h" #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/kernel_socket.h" extern struct zebra_privs_t zserv_privs; extern struct zebra_t zebrad; /* * Given a sockaddr length, round it up to include pad bytes following * it. Assumes the kernel pads to sizeof(long). * * XXX: why is ROUNDUP(0) sizeof(long)? 0 is an illegal sockaddr * length anyway (< sizeof (struct sockaddr)), so this shouldn't * matter. * On OS X, both 32, 64bit syatems align on 4 byte boundary */ #ifdef __APPLE__ #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int)) #else #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #endif /* * 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 */ /* * 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 void inline rta_copy (union sockunion *dest, caddr_t src) { int len; #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 ( ((DEST) != NULL) && \ 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)); \ if ((DEST) != NULL) \ 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 */ {RTF_XRESOLVE, "XRESOLVE"}, {RTF_LLINFO, "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 int inline 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_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 */ /* * 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 doesnt 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 */ if (ifnlen) { #ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN memcpy (&ifp->sdl, sdl, sdl->sdl_len); #else memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); #endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */ } 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) { switch (sockunion_family(addr)) { case AF_INET: { char buf[4][INET_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(AF_INET,&addr->sin.sin_addr, buf[0],sizeof(buf[0])), ip_masklen(mask->sin.sin_addr), inet_ntop(AF_INET,&brd->sin.sin_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET,&dst.sin.sin_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET,&gateway.sin.sin_addr, buf[3],sizeof(buf[3]))); } break; #ifdef HAVE_IPV6 case AF_INET6: { 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(AF_INET6,&addr->sin6.sin6_addr, buf[0],sizeof(buf[0])), ip6_masklen(mask->sin6.sin6_addr), inet_ntop(AF_INET6,&brd->sin6.sin6_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET6,&dst.sin6.sin6_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET6,&gateway.sin6.sin6_addr, buf[3],sizeof(buf[3]))); } break; #endif /* HAVE_IPV6 */ 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) && ! (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[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN]; int ret; if (! IS_ZEBRA_DEBUG_RIB) return; ret = rib_lookup_ipv4_route (&p, &gate); inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN); 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/%d: desync: RR isn't yet in RIB, while already in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); 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/%d: desync: RR is in RIB, but gate differs (ours is %s)", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf); break; case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s/%d: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); 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/%d: desync: RR is still in RIB, while already not in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s/%d: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); return; break; } break; default: zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received", __func__, buf, p.prefixlen, 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, 0, 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, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0, 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; unsigned int ifindex = 0; p.family = AF_INET6; p.prefix = dest.sin6.sin6_addr; if (flags & RTF_HOST) p.prefixlen = IPV6_MAX_PREFIXLEN; else p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) { ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); } #endif /* KAME */ /* 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, 0, 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, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0, 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) 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 && 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 *) & ifp->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); /* Additional flags. */ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; if (zebra_flags & ZEBRA_FLAG_REJECT) msg.rtm.rtm_flags |= RTF_REJECT; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP ((X)->sa.sa_len); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = SAROUNDUP (X); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ pnt = (caddr_t) msg.buf; /* Write each socket data into rtm message buffer */ SOCKADDRSET (dest, RTA_DST); SOCKADDRSET (gate, RTA_GATEWAY); SOCKADDRSET (mask, RTA_NETMASK); msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); if (ret != msg.rtm.rtm_msglen) { if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; 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 %d, rtm_addrs 0x%x", 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 (void) { 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 (void) { routing_socket (); } quagga-0.99.22.4/zebra/kernel_socket.h0000644000175000017500000000234312132522417014332 00000000000000/* * 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-0.99.22.4/zebra/main.c0000644000175000017500000002330412211105060012406 00000000000000/* 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 "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'}, { "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"\ "-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, }, }; /* 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; struct thread thread; char *zserv_path = 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:i:z:hA:P:ru:g:vs:C", longopts, 0); #else opt = getopt_long (argc, argv, "bdkf: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 '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_init(); zebra_vty_init (); access_list_init (); prefix_list_init (); #ifdef RTADV rtadv_init (); #endif #ifdef HAVE_IRDP irdp_init(); #endif /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ /* Make kernel routing socket. */ kernel_init (); interface_list (); route_read (); /* Sort VTY commands. */ sort_node (); #ifdef HAVE_SNMP zebra_snmp_init (); #endif /* HAVE_SNMP */ #ifdef HAVE_FPM zfpm_init (zebrad.master, 1, 0); #else zfpm_init (zebrad.master, 0, 0); #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); /* 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); while (thread_fetch (zebrad.master, &thread)) thread_call (&thread); /* Not reached... */ return 0; } quagga-0.99.22.4/zebra/misc_null.c0000644000175000017500000000125012177450262013465 00000000000000#include #include "prefix.h" #include "zebra/rtadv.h" #include "zebra/irdp.h" #include "zebra/interface.h" #include "zebra/zebra_fpm.h" void ifstat_update_proc (void) { return; } #ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA #pragma weak rtadv_config_write = ifstat_update_proc #pragma weak irdp_config_write = ifstat_update_proc #pragma weak ifstat_update_sysctl = ifstat_update_proc #else void rtadv_config_write (struct vty *vty, struct interface *ifp) { return; } void irdp_config_write (struct vty *vty, struct interface *ifp) { return; } void ifstat_update_sysctl (void) { return; } #endif void zfpm_trigger_update (struct route_node *rn, const char *reason) { return; } quagga-0.99.22.4/zebra/mtu_kvm.c0000644000175000017500000000411012132522417013151 00000000000000/* MTU get using kvm_read. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include #include "if.h" /* get interface MTU to use kvm_read */ void if_kvm_get_mtu (struct interface *ifp) { kvm_t *kvmd; struct ifnet ifnet; unsigned long ifnetaddr; int len; char ifname[IFNAMSIZ]; char tname[INTERFACE_NAMSIZ + 1]; char buf[_POSIX2_LINE_MAX]; struct nlist nl[] = { {"_ifnet"}, {""} }; ifp->mtu6 = ifp->mtu = -1; kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf); if (kvmd == NULL) return ; kvm_nlist(kvmd, nl); ifnetaddr = nl[0].n_value; if (kvm_read(kvmd, ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr) < 0) { kvm_close (kvmd); return ; } while(ifnetaddr != 0) { if (kvm_read (kvmd, ifnetaddr, (char *)&ifnet, sizeof ifnet) < 0) { kvm_close (kvmd); return ; } if (kvm_read (kvmd, (u_long)ifnet.if_name, ifname, IFNAMSIZ) < 0) { kvm_close (kvmd); return ; } len = snprintf (tname, INTERFACE_NAMSIZ + 1, "%s%d", ifname, ifnet.if_unit); if (strncmp (tname, ifp->name, len) == 0) break; ifnetaddr = (u_long)ifnet.if_next; } kvm_close (kvmd); if (ifnetaddr == 0) { return ; } ifp->mtu6 = ifp->mtu = ifnet.if_mtu; } quagga-0.99.22.4/zebra/redistribute.c0000644000175000017500000002360412177450262014214 00000000000000/* Redistribution Handler * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vector.h" #include "vty.h" #include "command.h" #include "prefix.h" #include "table.h" #include "stream.h" #include "zclient.h" #include "linklist.h" #include "log.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #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; } static 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) { struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; struct rib *newrib; #ifdef HAVE_IPV6 struct prefix_ipv6 p6; #endif /* HAVE_IPV6 */ /* Lookup default route. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) { rn = route_node_lookup (table, (struct prefix *)&p); if (rn) { 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 = vrf_table (AFI_IP6, SAFI_UNICAST, 0); 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) { struct rib *newrib; struct route_table *table; struct route_node *rn; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) 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)) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); #ifdef HAVE_IPV6 table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) 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)) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); #endif /* HAVE_IPV6 */ } void redistribute_add (struct prefix *p, struct rib *rib) { struct listnode *node, *nnode; struct zserv *client; for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { if (is_default (p)) { if (client->redist_default || client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); #endif /* HAVE_IPV6 */ } } else if (client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); #endif /* HAVE_IPV6 */ } } } 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)) { if (client->redist_default || client->redist[rib->type]) { 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 */ } } else if (client->redist[rib->type]) { 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) { int type; type = stream_getc (client->ibuf); if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; if (! client->redist[type]) { client->redist[type] = 1; zebra_redistribute (client, type); } } void zebra_redistribute_delete (int command, struct zserv *client, int length) { int type; type = stream_getc (client->ibuf); if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; client->redist[type] = 0; } void zebra_redistribute_default_add (int command, struct zserv *client, int length) { client->redist_default = 1; zebra_redistribute_default (client); } void zebra_redistribute_default_delete (int command, struct zserv *client, int length) { client->redist_default = 0;; } /* Interface up information. */ void zebra_interface_up_update (struct interface *ifp) { 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)) zsend_interface_update (ZEBRA_INTERFACE_UP, 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) zsend_interface_add (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) 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[INET6_ADDRSTRLEN]; p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s", inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), p->prefixlen, ifc->ifp->name); } 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)) 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[INET6_ADDRSTRLEN]; p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s", inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), p->prefixlen, 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)) zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); } quagga-0.99.22.4/zebra/redistribute.h0000644000175000017500000000351512132522417014211 00000000000000/* * 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); extern void zebra_redistribute_delete (int, struct zserv *, int); extern void zebra_redistribute_default_add (int, struct zserv *, int); extern void zebra_redistribute_default_delete (int, struct zserv *, int); extern void redistribute_add (struct prefix *, struct rib *); 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 int zebra_check_addr (struct prefix *); #endif /* _ZEBRA_REDISTRIBUTE_H */ quagga-0.99.22.4/zebra/redistribute_null.c0000644000175000017500000000342312177450262015243 00000000000000#include #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" void zebra_redistribute_add (int a, struct zserv *b, int c) { 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) { return; } void zebra_redistribute_default_add (int a, struct zserv *b, int c) { return; } void zebra_redistribute_default_delete (int a, struct zserv *b, int c) { return; } #endif void redistribute_add (struct prefix *a, struct rib *b) { 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 quagga-0.99.22.4/zebra/rib.h0000644000175000017500000003021612211105060012243 00000000000000/* * 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 "prefix.h" #include "table.h" #include "queue.h" #define DISTANCE_INFINITY 255 /* Routing information base. */ union g_addr { struct in_addr ipv4; #ifdef HAVE_IPV6 struct in6_addr ipv6; #endif /* HAVE_IPV6 */ }; struct rib { /* Link list. */ struct rib *next; struct rib *prev; /* Nexthop structure */ struct nexthop *nexthop; /* Refrence count. */ unsigned long refcnt; /* Uptime. */ time_t uptime; /* Type fo this route. */ int type; /* Which routing table */ int table; /* Metric */ u_int32_t metric; /* 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) /* 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_ipv4 { /* For linked list. */ struct static_ipv4 *prev; struct static_ipv4 *next; /* Administrative distance. */ u_char distance; /* Flag for this static route's type. */ u_char type; #define STATIC_IPV4_GATEWAY 1 #define STATIC_IPV4_IFNAME 2 #define STATIC_IPV4_BLACKHOLE 3 /* Nexthop value. */ union { struct in_addr ipv4; char *ifname; } gate; /* bit flags */ u_char flags; /* see ZEBRA_FLAG_REJECT ZEBRA_FLAG_BLACKHOLE */ }; #ifdef HAVE_IPV6 /* Static route information. */ struct static_ipv6 { /* For linked list. */ struct static_ipv6 *prev; struct static_ipv6 *next; /* Administrative distance. */ u_char distance; /* Flag for this static route's type. */ u_char type; #define STATIC_IPV6_GATEWAY 1 #define STATIC_IPV6_GATEWAY_IFNAME 2 #define STATIC_IPV6_IFNAME 3 /* Nexthop value. */ struct in6_addr ipv6; char *ifname; /* bit flags */ u_char flags; /* see ZEBRA_FLAG_REJECT ZEBRA_FLAG_BLACKHOLE */ }; #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; unsigned int 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. */ /* Nexthop address or interface name. */ union g_addr gate; /* Recursive lookup nexthop. */ u_char rtype; unsigned int rifindex; union g_addr rgate; union g_addr src; }; /* Routing table instance. */ struct vrf { /* Identifier. This is same as routing table vector index. */ u_int32_t id; /* Routing table name. */ char *name; /* Description. */ char *desc; /* FIB identifier. */ u_char fib_id; /* Routing table. */ struct route_table *table[AFI_MAX][SAFI_MAX]; /* Static route configuration. */ struct route_table *stable[AFI_MAX][SAFI_MAX]; }; /* * 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 vrf. */ struct vrf *vrf; 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_ { uint32_t vrf_id; int afi_safi_ix; rib_tables_iter_state_t state; } rib_tables_iter_t; extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern struct nexthop *nexthop_ifindex_add (struct rib *, unsigned int); extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, struct in_addr *); extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, struct in_addr *, struct in_addr *, unsigned int); extern void rib_lookup_and_dump (struct prefix_ipv4 *); extern void rib_lookup_and_pushup (struct prefix_ipv4 *); extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *); extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *); #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 #ifdef HAVE_IPV6 extern struct nexthop *nexthop_ipv6_add (struct rib *, struct in6_addr *); #endif /* HAVE_IPV6 */ extern struct vrf *vrf_lookup (u_int32_t); extern struct route_table *vrf_table (afi_t afi, safi_t safi, u_int32_t id); extern struct route_table *vrf_static_table (afi_t afi, safi_t safi, u_int32_t id); /* 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, unsigned int ifindex, u_int32_t vrf_id, 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, unsigned int ifindex, u_int32_t, safi_t safi); extern struct rib *rib_match_ipv4 (struct in_addr); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); extern void rib_update (void); extern void rib_weed_tables (void); extern void rib_sweep_route (void); extern void rib_close (void); extern void rib_init (void); extern unsigned long rib_score_proto (u_char proto); extern int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, u_char flags, u_char distance, u_int32_t vrf_id); extern int static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, u_char distance, u_int32_t vrf_id); #ifdef HAVE_IPV6 extern int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, u_int32_t metric, u_char distance, safi_t safi); extern int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, safi_t safi); extern struct rib *rib_lookup_ipv6 (struct in6_addr *); extern struct rib *rib_match_ipv6 (struct in6_addr *); 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, u_char distance, u_int32_t vrf_id); extern int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char distance, u_int32_t vrf_id); #endif /* HAVE_IPV6 */ 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 vrf * rib_dest_vrf (rib_dest_t *dest) { return rib_table_info (rib_dest_table (dest))->vrf; } /* * 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-0.99.22.4/zebra/router-id.c0000644000175000017500000001334712132522417013415 00000000000000/* * 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 "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" static struct list rid_all_sorted_list; static struct list rid_lo_sorted_list; static struct prefix rid_user_assigned; /* 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) { struct listnode *node; struct connected *c; p->u.prefix4.s_addr = 0; p->family = AF_INET; p->prefixlen = 32; if (rid_user_assigned.u.prefix4.s_addr) p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr; else if (!list_isempty (&rid_lo_sorted_list)) { node = listtail (&rid_lo_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } else if (!list_isempty (&rid_all_sorted_list)) { node = listtail (&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) { struct prefix p2; struct listnode *node; struct zserv *client; rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr; router_id_get (&p2); for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &p2); } void router_id_add_address (struct connected *ifc) { struct list *l = NULL; struct listnode *node; struct prefix before; struct prefix after; struct zserv *client; if (router_id_bad_address (ifc)) return; router_id_get (&before); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) l = &rid_lo_sorted_list; else l = &rid_all_sorted_list; if (!router_id_find_node (l, ifc)) listnode_add_sort (l, ifc); router_id_get (&after); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &after); } 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; if (router_id_bad_address (ifc)) return; router_id_get (&before); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) l = &rid_lo_sorted_list; else l = &rid_all_sorted_list; if ((c = router_id_find_node (l, ifc))) listnode_delete (l, c); router_id_get (&after); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &after); } void router_id_write (struct vty *vty) { if (rid_user_assigned.u.prefix4.s_addr) vty_out (vty, "router-id %s%s", inet_ntoa (rid_user_assigned.u.prefix4), 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; 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; router_id_set (&rid); return CMD_SUCCESS; } DEFUN (no_router_id, no_router_id_cmd, "no router-id", NO_STR "Remove the manually configured router-id\n") { struct prefix rid; rid.u.prefix4.s_addr = 0; rid.prefixlen = 0; rid.family = AF_INET; router_id_set (&rid); return CMD_SUCCESS; } 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; unsigned int A = ntohl(ifa->address->u.prefix4.s_addr); unsigned int B = ntohl(ifb->address->u.prefix4.s_addr); return (int) (A - B); } void router_id_init (void) { install_element (CONFIG_NODE, &router_id_cmd); install_element (CONFIG_NODE, &no_router_id_cmd); memset (&rid_all_sorted_list, 0, sizeof (rid_all_sorted_list)); memset (&rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list)); memset (&rid_user_assigned, 0, sizeof (rid_user_assigned)); rid_all_sorted_list.cmp = router_id_cmp; rid_lo_sorted_list.cmp = router_id_cmp; rid_user_assigned.family = AF_INET; rid_user_assigned.prefixlen = 32; } quagga-0.99.22.4/zebra/router-id.h0000644000175000017500000000230512132522417013412 00000000000000/* * 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(void); extern void router_id_write(struct vty *); extern void router_id_get(struct prefix *); #endif quagga-0.99.22.4/zebra/rt.h0000644000175000017500000000314612132522417012131 00000000000000/* * 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_add_ipv4 (struct prefix *, struct rib *); extern int kernel_delete_ipv4 (struct prefix *, 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 *); #ifdef HAVE_IPV6 extern int kernel_add_ipv6 (struct prefix *, struct rib *); extern int kernel_delete_ipv6 (struct prefix *, struct rib *); extern int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table); #endif /* HAVE_IPV6 */ #endif /* _ZEBRA_RT_H */ quagga-0.99.22.4/zebra/rt_ioctl.c0000644000175000017500000003303712132522417013320 00000000000000/* * kernel routing table update by ioctl(). * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "log.h" #include "if.h" #include "zebra/zserv.h" #include "zebra/rib.h" #include "zebra/debug.h" #include "zebra/rt.h" /* Initialize of kernel interface. There is no kernel communication support under ioctl(). So this is dummy stub function. */ void kernel_init (void) { return; } /* Dummy function of routing socket. */ static void kernel_read (int sock) { return; } #if 0 /* Initialization prototype of struct sockaddr_in. */ static struct sockaddr_in sin_proto = { #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sizeof (struct sockaddr_in), #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ AF_INET, 0, {0}, {0} }; #endif /* 0 */ /* Solaris has ortentry. */ #ifdef HAVE_OLD_RTENTRY #define rtentry ortentry #endif /* HAVE_OLD_RTENTRY */ /* Interface to ioctl route message. */ int kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate, int index, int flags) { int ret; int sock; struct rtentry rtentry; struct sockaddr_in sin_dest, sin_mask, sin_gate; memset (&rtentry, 0, sizeof (struct rtentry)); /* Make destination. */ memset (&sin_dest, 0, sizeof (struct sockaddr_in)); sin_dest.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_dest.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_dest.sin_addr = dest->prefix; /* Make gateway. */ if (gate) { memset (&sin_gate, 0, sizeof (struct sockaddr_in)); sin_gate.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_gate.sin_addr = *gate; } memset (&sin_mask, 0, sizeof (struct sockaddr_in)); sin_mask.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 */ masklen2ip (dest->prefixlen, &sin_mask.sin_addr); /* Set destination address, mask and gateway.*/ memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); if (gate) memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); #ifndef SUNOS_5 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); #endif /* SUNOS_5 */ /* Routing entry flag set. */ if (dest->prefixlen == 32) rtentry.rt_flags |= RTF_HOST; if (gate && gate->s_addr != INADDR_ANY) rtentry.rt_flags |= RTF_GATEWAY; rtentry.rt_flags |= RTF_UP; /* Additional flags */ rtentry.rt_flags |= flags; /* For tagging route. */ /* rtentry.rt_flags |= RTF_DYNAMIC; */ /* Open socket for ioctl. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("can't make socket\n"); return -1; } /* Send message by ioctl(). */ ret = ioctl (sock, SIOCADDRT, &rtentry); if (ret < 0) { switch (errno) { case EEXIST: close (sock); return ZEBRA_ERR_RTEXIST; break; case ENETUNREACH: close (sock); return ZEBRA_ERR_RTUNREACH; break; case EPERM: close (sock); return ZEBRA_ERR_EPERM; break; } close (sock); zlog_warn ("write : %s (%d)", safe_strerror (errno), errno); return 1; } close (sock); return ret; } /* Interface to ioctl route message. */ static int kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family) { int ret; int sock; struct rtentry rtentry; struct sockaddr_in sin_dest, sin_mask, sin_gate; struct nexthop *nexthop; int nexthop_num = 0; struct interface *ifp; memset (&rtentry, 0, sizeof (struct rtentry)); /* Make destination. */ memset (&sin_dest, 0, sizeof (struct sockaddr_in)); sin_dest.sin_family = AF_INET; #ifdef HAVE_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; if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) { SET_FLAG (rtentry.rt_flags, RTF_REJECT); if (cmd == SIOCADDRT) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); goto skip; } memset (&sin_gate, 0, sizeof (struct sockaddr_in)); /* Make gateway. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if ((cmd == SIOCADDRT && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == SIOCDELRT && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { sin_gate.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_gate.sin_addr = nexthop->rgate.ipv4; rtentry.rt_flags |= RTF_GATEWAY; } if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME) { ifp = if_lookup_by_index (nexthop->rifindex); if (ifp) rtentry.rt_dev = ifp->name; else return -1; } } else { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { sin_gate.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_gate.sin_addr = nexthop->gate.ipv4; rtentry.rt_flags |= RTF_GATEWAY; } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) { ifp = if_lookup_by_index (nexthop->ifindex); if (ifp) rtentry.rt_dev = ifp->name; else return -1; } } if (cmd == SIOCADDRT) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); nexthop_num++; break; } } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_route_multipath(): No useful nexthop."); return 0; } skip: memset (&sin_mask, 0, sizeof (struct sockaddr_in)); sin_mask.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_mask.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ masklen2ip (p->prefixlen, &sin_mask.sin_addr); /* Set destination address, mask and gateway.*/ memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in)); if (rtentry.rt_flags & RTF_GATEWAY) memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in)); #ifndef SUNOS_5 memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in)); #endif /* SUNOS_5 */ /* Metric. It seems metric minus one value is installed... */ rtentry.rt_metric = rib->metric; /* Routing entry flag set. */ if (p->prefixlen == 32) rtentry.rt_flags |= RTF_HOST; rtentry.rt_flags |= RTF_UP; /* Additional flags */ /* rtentry.rt_flags |= flags; */ /* For tagging route. */ /* rtentry.rt_flags |= RTF_DYNAMIC; */ /* Open socket for ioctl. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("can't make socket\n"); return -1; } /* Send message by ioctl(). */ ret = ioctl (sock, cmd, &rtentry); if (ret < 0) { switch (errno) { case EEXIST: close (sock); return ZEBRA_ERR_RTEXIST; break; case ENETUNREACH: close (sock); return ZEBRA_ERR_RTUNREACH; break; case EPERM: close (sock); return ZEBRA_ERR_EPERM; break; } close (sock); zlog_warn ("write : %s (%d)", safe_strerror (errno), errno); return ret; } close (sock); return ret; } int kernel_add_ipv4 (struct prefix *p, struct rib *rib) { return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET); } int kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET); } #ifdef HAVE_IPV6 /* Below is hack for GNU libc definition and Linux 2.1.X header. */ #undef RTF_DEFAULT #undef RTF_ADDRCONF #include #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 /* struct in6_rtmsg will be declared in net/route.h. */ #else #include #endif static int kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate, int index, int flags) { int ret; int sock; struct in6_rtmsg rtm; memset (&rtm, 0, sizeof (struct in6_rtmsg)); rtm.rtmsg_flags |= RTF_UP; rtm.rtmsg_metric = 1; memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr)); rtm.rtmsg_dst_len = dest->prefixlen; /* We need link local index. But this should be done caller... if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) { index = if_index_address (&rtm.rtmsg_gateway); rtm.rtmsg_ifindex = index; } else rtm.rtmsg_ifindex = 0; */ rtm.rtmsg_flags |= RTF_GATEWAY; /* For tagging route. */ /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr)); if (index) rtm.rtmsg_ifindex = index; else rtm.rtmsg_ifindex = 0; rtm.rtmsg_metric = 1; sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("can't make socket\n"); return -1; } /* Send message via ioctl. */ ret = ioctl (sock, type, &rtm); if (ret < 0) { zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", safe_strerror(errno)); ret = errno; close (sock); return ret; } close (sock); return ret; } static int kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib, int family) { int ret; int sock; struct in6_rtmsg rtm; struct nexthop *nexthop; int nexthop_num = 0; memset (&rtm, 0, sizeof (struct in6_rtmsg)); rtm.rtmsg_flags |= RTF_UP; rtm.rtmsg_metric = rib->metric; memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr)); rtm.rtmsg_dst_len = p->prefixlen; /* We need link local index. But this should be done caller... if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway)) { index = if_index_address (&rtm.rtmsg_gateway); rtm.rtmsg_ifindex = index; } else rtm.rtmsg_ifindex = 0; */ rtm.rtmsg_flags |= RTF_GATEWAY; /* For tagging route. */ /* rtm.rtmsg_flags |= RTF_DYNAMIC; */ /* Make gateway. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if ((cmd == SIOCADDRT && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == SIOCDELRT && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (nexthop->rtype == NEXTHOP_TYPE_IPV6 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) { memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6, sizeof (struct in6_addr)); } if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) rtm.rtmsg_ifindex = nexthop->rifindex; else rtm.rtmsg_ifindex = 0; } else { if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6, sizeof (struct in6_addr)); } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) rtm.rtmsg_ifindex = nexthop->ifindex; else rtm.rtmsg_ifindex = 0; } if (cmd == SIOCADDRT) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); nexthop_num++; break; } } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_route_multipath(): No useful nexthop."); return 0; } sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("can't make socket\n"); return -1; } /* Send message via ioctl. */ ret = ioctl (sock, cmd, &rtm); if (ret < 0) { zlog_warn ("can't %s ipv6 route: %s\n", cmd == SIOCADDRT ? "add" : "delete", safe_strerror(errno)); ret = errno; close (sock); return ret; } close (sock); return ret; } int kernel_add_ipv6 (struct prefix *p, struct rib *rib) { return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6); } int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6); } /* Delete IPv6 route from the kernel. */ int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table) { return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags); } #endif /* HAVE_IPV6 */ quagga-0.99.22.4/zebra/rt_netlink.c0000644000175000017500000015747012211704467013667 00000000000000/* Kernel routing table updates using netlink over GNU/Linux system. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include /* Hack for GNU libc version 2. */ #ifndef MSG_TRUNC #define MSG_TRUNC 0x20 #endif /* MSG_TRUNC */ #include "linklist.h" #include "if.h" #include "log.h" #include "prefix.h" #include "connected.h" #include "table.h" #include "memory.h" #include "rib.h" #include "thread.h" #include "privs.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" /* Socket interface to kernel */ struct nlsock { int sock; int seq; struct sockaddr_nl snl; const char *name; } netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */ netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */ 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; /* 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, unsigned int 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; } 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; } 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) { int ret; struct sockaddr_nl snl; int sock; int namelen; int save_errno; sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 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. */ if (zserv_privs.change (ZPRIVS_RAISE)) { zlog (NULL, LOG_ERR, "Can't raise privileges"); return -1; } 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 *), struct nlsock *nl) { int status; int ret = 0; int error; while (1) { char buf[NL_PKT_BUF_SIZE]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; struct nlmsghdr *h; status = recvmsg (nl->sock, &msg, 0); if (status < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) break; zlog (NULL, LOG_ERR, "%s recvmsg overrun: %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 *) buf; 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 == &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 */ if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s packet comes from %s", netlink_cmd.name, nl->name); continue; } error = (*filter) (&snl, h); if (error < 0) { zlog (NULL, LOG_ERR, "%s filter function error", nl->name); ret = error; } } /* After error care. */ if (msg.msg_flags & MSG_TRUNC) { zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); continue; } if (status) { zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name, status); return -1; } } return ret; } /* Utility function for parse rtattr. */ static void netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len) { while (RTA_OK (rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT (rta, len); } } /* 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; } } } /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; 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 (name); 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 = 1; /* Hardware type and address. */ ifp->hw_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) { 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 (ifa->ifa_index); if (ifp == NULL) { zlog_err ("netlink_interface_addr can't find interface by index %d", ifa->ifa_index); return -1; } if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; zlog_debug ("netlink_interface_addr %s %s:", lookup (nlmsg_str, h->nlmsg_type), ifp->name); 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) { int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char flags = 0; char anyaddr[16] = { 0 }; int index; int table; int metric; 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; metric = 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_PRIORITY]) metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); 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, table, metric, 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 = metric; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); for (;;) { if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; rib->nexthop_num++; 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) nexthop_ipv4_ifindex_add (rib, gate, src, index); else nexthop_ipv4_add (rib, gate, src); } else 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, table, metric, 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) { int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; char anyaddr[16] = { 0 }; int index; int table; int metric; 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\n", h->nlmsg_type); return 0; } /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s %s %s proto %s", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", lookup (rtproto_str, rtm->rtm_protocol)); if (rtm->rtm_type != RTN_UNICAST) { return 0; } table = rtm->rtm_table; if (table != RT_TABLE_MAIN && table != 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_src_len != 0) { zlog_warn ("netlink_route_change(): no src len"); return 0; } index = 0; metric = 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 && tb[RTA_PRIORITY]) metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_debug ("RTM_NEWROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); else zlog_debug ("RTM_DELROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) { if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 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 = metric; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); for (;;) { if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; rib->nexthop_num++; 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) nexthop_ipv4_ifindex_add (rib, gate, src, index); else nexthop_ipv4_add (rib, gate, src); } else 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, 0, &p, gate, index, table, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; char buf[BUFSIZ]; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_debug ("RTM_NEWROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); else zlog_debug ("RTM_DELROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ return 0; } static int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); #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. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; 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 = 1; 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 (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", name); return 0; } if_delete_update (ifp); } return 0; } static int netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) { /* 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); break; case RTM_DELROUTE: return netlink_route_change (snl, h); break; case RTM_NEWLINK: return netlink_link_change (snl, h); break; case RTM_DELLINK: return netlink_link_change (snl, h); break; case RTM_NEWADDR: return netlink_interface_addr (snl, h); break; case RTM_DELADDR: return netlink_interface_addr (snl, h); break; default: zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type); break; } return 0; } /* Interface lookup by netlink socket. */ int interface_lookup_netlink (void) { int ret; /* Get interface information. */ ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface, &netlink_cmd); if (ret < 0) return ret; /* Get IPv4 address of the interfaces. */ ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 address of the interfaces. */ ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ return 0; } /* Routing table read function using netlink interface. Only called bootstrap time. */ int netlink_route_read (void) { int ret; /* Get IPv4 routing table. */ ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 routing table. */ ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ return 0; } /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { int len; struct rtattr *rta; len = RTA_LENGTH (alen); if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA (rta), data, alen); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0; } int rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) { int len; struct rtattr *subrta; len = RTA_LENGTH (alen); if (RTA_ALIGN (rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy (RTA_DATA (subrta), data, alen); rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len; return 0; } /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int addattr32 (struct nlmsghdr *n, int maxlen, int type, int data) { int len; struct rtattr *rta; len = RTA_LENGTH (4); if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA (rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0; } static int netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) { zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); return 0; } /* sendmsg() to netlink socket then recvmsg(). */ static int netlink_talk (struct nlmsghdr *n, struct nlsock *nl) { int status; struct sockaddr_nl snl; struct iovec iov = { (void *) n, n->nlmsg_len }; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; int 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); } /* Routing table change via netlink interface. */ static int netlink_route (int cmd, int family, void *dest, int length, void *gate, int index, int zebra_flags, int table) { int ret; int bytelen; struct sockaddr_nl snl; int discard; struct { struct nlmsghdr n; struct rtmsg r; char buf[NL_PKT_BUF_SIZE]; } req; 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_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = table; req.r.rtm_dst_len = length; req.r.rtm_protocol = RTPROT_ZEBRA; req.r.rtm_scope = RT_SCOPE_UNIVERSE; if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE) || (zebra_flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { if (discard) { if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) req.r.rtm_type = RTN_BLACKHOLE; else if (zebra_flags & ZEBRA_FLAG_REJECT) req.r.rtm_type = RTN_UNREACHABLE; else assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ } else req.r.rtm_type = RTN_UNICAST; } if (dest) addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); if (!discard) { if (gate) addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen); if (index > 0) addattr32 (&req.n, sizeof req, RTA_OIF, index); } /* Destination netlink address. */ memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; /* Talk to netlink socket. */ ret = netlink_talk (&req.n, &netlink_cmd); if (ret < 0) return -1; return 0; } /* Routing table change via netlink interface. */ static int netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, int family) { int bytelen; struct sockaddr_nl snl; struct nexthop *nexthop = NULL; int nexthop_num = 0; int discard; struct { struct nlmsghdr n; struct rtmsg r; char buf[NL_PKT_BUF_SIZE]; } req; 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_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_UNIVERSE; 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, rib->metric); if (discard) { if (cmd == RTM_NEWROUTE) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); goto skip; } /* Multipath case. */ if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) { for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("netlink_route_multipath() (recursive, 1 hop): " "%s %s/%d, type %s", lookup (nlmsg_str, cmd), #ifdef HAVE_IPV6 (family == AF_INET) ? inet_ntoa (p->u.prefix4) : inet6_ntoa (p->u.prefix6), #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ p->prefixlen, nexthop_type_to_str (nexthop->rtype)); } if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { addattr_l (&req.n, sizeof req, RTA_GATEWAY, &nexthop->rgate.ipv4, bytelen); if (nexthop->src.ipv4.s_addr) addattr_l(&req.n, sizeof req, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "1 hop): nexthop via %s if %u", inet_ntoa (nexthop->rgate.ipv4), nexthop->rifindex); } #ifdef HAVE_IPV6 if (nexthop->rtype == NEXTHOP_TYPE_IPV6 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) { addattr_l (&req.n, sizeof req, RTA_GATEWAY, &nexthop->rgate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "1 hop): nexthop via %s if %u", inet6_ntoa (nexthop->rgate.ipv6), nexthop->rifindex); } #endif /* HAVE_IPV6 */ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) { addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->rifindex); if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFINDEX) && nexthop->src.ipv4.s_addr) addattr_l (&req.n, sizeof req, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "1 hop): nexthop via if %u", nexthop->rifindex); } } else { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("netlink_route_multipath() (single hop): " "%s %s/%d, type %s", lookup (nlmsg_str, cmd), #ifdef HAVE_IPV6 (family == AF_INET) ? inet_ntoa (p->u.prefix4) : inet6_ntoa (p->u.prefix6), #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ p->prefixlen, nexthop_type_to_str (nexthop->type)); } if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { addattr_l (&req.n, sizeof req, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); if (nexthop->src.ipv4.s_addr) addattr_l (&req.n, sizeof req, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (single hop): " "nexthop via %s if %u", 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 (&req.n, sizeof req, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (single hop): " "nexthop via %s if %u", 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 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex); if (nexthop->src.ipv4.s_addr) addattr_l (&req.n, sizeof req, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (single hop): " "nexthop via if %u", nexthop->ifindex); } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) { addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (single hop): " "nexthop via if %u", nexthop->ifindex); } } 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 (nexthop = rib->nexthop; nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM); nexthop = nexthop->next) { if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { nexthop_num++; rtnh->rtnh_len = sizeof (*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rta->rta_len += rtnh->rtnh_len; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("netlink_route_multipath() " "(recursive, multihop): %s %s/%d type %s", lookup (nlmsg_str, cmd), #ifdef HAVE_IPV6 (family == AF_INET) ? inet_ntoa (p->u.prefix4) : inet6_ntoa (p->u.prefix6), #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ p->prefixlen, nexthop_type_to_str (nexthop->rtype)); } if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->rgate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + 4; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "multihop): nexthop via %s if %u", inet_ntoa (nexthop->rgate.ipv4), nexthop->rifindex); } #ifdef HAVE_IPV6 if (nexthop->rtype == NEXTHOP_TYPE_IPV6 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->rgate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "multihop): nexthop via %s if %u", inet6_ntoa (nexthop->rgate.ipv6), nexthop->rifindex); } #endif /* HAVE_IPV6 */ /* ifindex */ if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME) { rtnh->rtnh_ifindex = nexthop->rifindex; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "multihop): nexthop via if %u", nexthop->rifindex); } else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) { rtnh->rtnh_ifindex = nexthop->rifindex; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (recursive, " "multihop): nexthop via if %u", nexthop->rifindex); } else { rtnh->rtnh_ifindex = 0; } } else { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("netlink_route_multipath() (multihop): " "%s %s/%d, type %s", lookup (nlmsg_str, cmd), #ifdef HAVE_IPV6 (family == AF_INET) ? inet_ntoa (p->u.prefix4) : inet6_ntoa (p->u.prefix6), #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ p->prefixlen, nexthop_type_to_str (nexthop->type)); } 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) + 4; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (multihop): " "nexthop via %s if %u", 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); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (multihop): " "nexthop via %s if %u", 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() (multihop): " "nexthop via if %u", 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() (multihop): " "nexthop via if %u", nexthop->ifindex); } else { rtnh->rtnh_ifindex = 0; } } 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, &netlink_cmd); } int kernel_add_ipv4 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET); } int kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET); } #ifdef HAVE_IPV6 int kernel_add_ipv6 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6); } int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); } /* Delete IPv6 route from the kernel. */ int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table) { return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, dest->prefixlen, gate, index, flags, table); } #endif /* HAVE_IPV6 */ /* Interface address modification. */ 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; 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, &netlink_cmd); } int kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc) { return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc); } int kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) { return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc); } extern struct thread_master *master; /* Kernel route reflection. */ static int kernel_read (struct thread *thread) { netlink_parse_info (netlink_information_fetch, &netlink); thread_add_read (zebrad.master, kernel_read, NULL, 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 (void) { unsigned long groups; groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR; #ifdef HAVE_IPV6 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR; #endif /* HAVE_IPV6 */ netlink_socket (&netlink, groups); netlink_socket (&netlink_cmd, 0); /* Register kernel socket. */ if (netlink.sock > 0) { /* Only want non-blocking on the netlink event socket */ if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0) zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name, safe_strerror (errno)); /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) netlink_recvbuf (&netlink, nl_rcvbufsize); netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid); thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); } } /* * 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-0.99.22.4/zebra/rt_netlink.h0000644000175000017500000000257212177450262013666 00000000000000/* 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 extern int addattr32 (struct nlmsghdr *n, int maxlen, int type, int data); extern int addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen); extern int rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen); extern const char * nl_msg_type_to_str (uint16_t msg_type); extern const char * nl_rtproto_to_str (u_char rtproto); #endif /* HAVE_NETLINK */ #endif /* _ZEBRA_RT_NETLINK_H */ quagga-0.99.22.4/zebra/rt_socket.c0000644000175000017500000003466712132522417013510 00000000000000/* * 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); /* 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; } /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) { struct sockaddr_in *mask = NULL; struct sockaddr_in sin_dest, sin_mask, sin_gate; struct nexthop *nexthop; int nexthop_num = 0; unsigned int ifindex = 0; int gate = 0; int error; char prefix_buf[INET_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_RIB) inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); 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 (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { 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 (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { sin_gate.sin_addr = nexthop->rgate.ipv4; gate = 1; } if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) ifindex = nexthop->rifindex; } else { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { sin_gate.sin_addr = nexthop->gate.ipv4; gate = 1; } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) ifindex = nexthop->ifindex; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { struct in_addr loopback; loopback.s_addr = htonl (INADDR_LOOPBACK); sin_gate.sin_addr = loopback; gate = 1; } } if (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/%d: attention! gate not found for rib %p", __func__, prefix_buf, p->prefixlen, rib); rib_dump (__func__, (struct prefix_ipv4 *)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/%d: successfully did NH %s", __func__, prefix_buf, p->prefixlen, 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: /* This point is reachable regardless of debugging mode. */ if (!IS_ZEBRA_DEBUG_RIB) inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s", __func__, prefix_buf, p->prefixlen, 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 (nexthop = ... */ /* 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*/ } int kernel_add_ipv4 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } int kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } #ifdef HAVE_IPV6 /* 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 defined (INRIA) if (IN_ANYADDR6 (mask)) return sizeof (long); #else /* ! INRIA */ if (IN6_IS_ADDR_UNSPECIFIED (&mask)) return sizeof (long); #endif /* ! INRIA */ sin6.sin6_addr = mask; len = sizeof (struct sockaddr_in6); lim = (char *) & sin6.sin6_addr; p = lim + sizeof (sin6.sin6_addr); while (*--p == 0 && p >= lim) len--; return len; } /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, struct in6_addr *gate, int index, int flags) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); sin_dest.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_dest.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); sin_gate.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_gate.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ sin_dest.sin6_addr = dest->prefix; if (gate) memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr)); /* Under kame set interface index to link local address. */ #ifdef KAME #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ do { \ (a).s6_addr[2] = ((i) >> 8) & 0xff; \ (a).s6_addr[3] = (i) & 0xff; \ } while (0) if (gate && IN6_IS_ADDR_LINKLOCAL(gate)) SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index); #endif /* KAME */ if (gate && dest->prefixlen == 128) mask = NULL; else { masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr); sin_mask.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); #endif /* SIN6_LEN */ mask = &sin_mask; } return rtm_write (message, (union sockunion *) &sin_dest, (union sockunion *) mask, gate ? (union sockunion *)&sin_gate : NULL, index, flags, 0); } /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, int family) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; struct nexthop *nexthop; int nexthop_num = 0; unsigned int ifindex = 0; int gate = 0; int error; memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); sin_dest.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_dest.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ sin_dest.sin6_addr = p->u.prefix6; memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); sin_gate.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin6_len = sizeof (struct sockaddr_in6); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { gate = 0; if ((cmd == RTM_ADD && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELETE #if 0 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) #endif )) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (nexthop->rtype == NEXTHOP_TYPE_IPV6 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) { sin_gate.sin6_addr = nexthop->rgate.ipv6; gate = 1; } if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX) ifindex = nexthop->rifindex; } else { if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { sin_gate.sin6_addr = nexthop->gate.ipv6; gate = 1; } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) ifindex = nexthop->ifindex; } if (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_multipath(): nexthop %d add error=%d.", nexthop_num, error); } #endif nexthop_num++; } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop."); return 0; } return 0; /*XXX*/ } int kernel_add_ipv6 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } /* Delete IPv6 route from the kernel. */ int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } #endif /* HAVE_IPV6 */ quagga-0.99.22.4/zebra/rtadv.c0000644000175000017500000014401412132522417012617 00000000000000/* 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 "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 (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 (enum rtadv_event, int); static int if_join_all_router (int, struct interface *); static int if_leave_all_router (int, struct interface *); /* 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; }; struct rtadv *rtadv = NULL; static struct rtadv * rtadv_new (void) { return XCALLOC (MTYPE_TMP, sizeof (struct rtadv)); } static int rtadv_recv_packet (int sock, u_char *buf, int buflen, struct sockaddr_in6 *from, unsigned int *ifindex, int *hoplimit) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_addr dst; char adata[1024]; /* Fill in message and iovec. */ msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = buflen; /* If recvmsg fail return minus value. */ ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (cmsgptr = 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. */ #ifdef HAVE_STRUCT_SOCKADDR_DL sdl = &ifp->sdl; if (sdl != NULL && sdl->sdl_alen != 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++] = (sdl->sdl_alen + 9) >> 3; memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen); len += sdl->sdl_alen; /* Pad option to end on an octet boundary. */ memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7); len += -(sdl->sdl_alen + 2) & 0x7; } #else 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; } #endif /* HAVE_STRUCT_SOCKADDR_DL */ /* 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 listnode *node, *nnode; struct interface *ifp; struct zebra_if *zif; int period; rtadv->ra_timer = NULL; if (rtadv->adv_msec_if_count == 0) { period = 1000; /* 1 s */ rtadv_event (RTADV_TIMER, 1 /* 1 s */); } else { period = 10; /* 10 ms */ rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */); } for (ALL_LIST_ELEMENTS (iflist, 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 (rtadv->sock, ifp); } } } return 0; } static void rtadv_process_solicit (struct interface *ifp) { zlog_info ("Router solicitation received on %s", ifp->name); rtadv_send_packet (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, unsigned int ifindex, int hoplimit) { struct icmp6_hdr *icmph; struct interface *ifp; struct zebra_if *zif; /* Interface search. */ ifp = if_lookup_by_index (ifindex); if (ifp == NULL) { zlog_warn ("Unknown interface index: %d", ifindex); return; } if (if_is_loopback (ifp)) return; /* Check interface configuration. */ zif = ifp->info; if (! zif->rtadv.AdvSendAdvertisements) return; /* ICMP message length check. */ if (len < sizeof (struct icmp6_hdr)) { zlog_warn ("Invalid ICMPV6 packet length: %d", len); return; } icmph = (struct icmp6_hdr *) buf; /* ICMP message type check. */ if (icmph->icmp6_type != ND_ROUTER_SOLICIT && icmph->icmp6_type != ND_ROUTER_ADVERT) { zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type); return; } /* Hoplimit check. */ if (hoplimit >= 0 && hoplimit != 255) { zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet", hoplimit); return; } /* Check ICMP message type. */ if (icmph->icmp6_type == ND_ROUTER_SOLICIT) rtadv_process_solicit (ifp); else if (icmph->icmp6_type == ND_ROUTER_ADVERT) rtadv_process_advert (); return; } static int rtadv_read (struct thread *thread) { int sock; int len; u_char buf[RTADV_MSG_SIZE]; struct sockaddr_in6 from; unsigned int ifindex = 0; int hoplimit = -1; sock = THREAD_FD (thread); rtadv->ra_read = NULL; /* Register myself. */ rtadv_event (RTADV_READ, sock); len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); if (len < 0) { zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno)); return len; } rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit); return 0; } static int rtadv_make_socket (void) { 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 = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 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) return -1; ret = setsockopt_ipv6_pktinfo (sock, 1); if (ret < 0) return ret; ret = setsockopt_ipv6_multicast_loop (sock, 0); if (ret < 0) return ret; ret = setsockopt_ipv6_unicast_hops (sock, 255); if (ret < 0) return ret; ret = setsockopt_ipv6_multicast_hops (sock, 255); if (ret < 0) return ret; ret = setsockopt_ipv6_hoplimit (sock, 1); if (ret < 0) return ret; ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter); ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter); ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (struct icmp6_filter)); if (ret < 0) { zlog_info ("ICMP6_FILTER set fail: %s", 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; ifp = vty->index; zif = ifp->info; if (if_is_loopback (ifp)) { vty_out (vty, "Invalid interface%s", VTY_NEWLINE); return CMD_WARNING; } if (zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 0; zif->rtadv.AdvIntervalTimer = 0; rtadv->adv_if_count--; if_leave_all_router (rtadv->sock, ifp); if (rtadv->adv_if_count == 0) rtadv_event (RTADV_STOP, 0); } return CMD_SUCCESS; } 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; ifp = vty->index; zif = ifp->info; if (if_is_loopback (ifp)) { vty_out (vty, "Invalid interface%s", VTY_NEWLINE); return CMD_WARNING; } if (! zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 1; zif->rtadv.AdvIntervalTimer = 0; rtadv->adv_if_count++; if_join_all_router (rtadv->sock, ifp); if (rtadv->adv_if_count == 1) rtadv_event (RTADV_START, rtadv->sock); } return CMD_SUCCESS; } 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; 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) rtadv->adv_msec_if_count--; if (interval % 1000) 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; 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) 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; ifp = (struct interface *) vty->index; zif = ifp->info; if (zif->rtadv.MaxRtrAdvInterval % 1000) 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(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; u_char buf[INET6_ADDRSTRLEN]; int interval; if (! rtadv) return; zif = ifp->info; if (! if_is_loopback (ifp)) { if (zif->rtadv.AdvSendAdvertisements) vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); else vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE); } 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/%d", inet_ntop (AF_INET6, &rprefix->prefix.prefix, (char *) buf, INET6_ADDRSTRLEN), rprefix->prefix.prefixlen); 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 (enum rtadv_event event, int val) { switch (event) { case RTADV_START: if (! rtadv->ra_read) rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer, NULL, 0); break; case RTADV_STOP: if (rtadv->ra_timer) { thread_cancel (rtadv->ra_timer); rtadv->ra_timer = NULL; } if (rtadv->ra_read) { thread_cancel (rtadv->ra_read); rtadv->ra_read = NULL; } break; case RTADV_TIMER: if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL, val); break; case RTADV_TIMER_MSEC: if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer, NULL, val); break; case RTADV_READ: if (! rtadv->ra_read) rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); break; default: break; } return; } void rtadv_init (void) { int sock; sock = rtadv_make_socket (); if (sock < 0) return; rtadv = rtadv_new (); rtadv->sock = sock; install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); install_element (INTERFACE_NODE, &ipv6_nd_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 (void) { /* Empty.*/; } #endif /* RTADV && HAVE_IPV6 */ quagga-0.99.22.4/zebra/rtadv.h0000644000175000017500000000624012177450262012631 00000000000000/* 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 */ #ifdef 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 *); extern void rtadv_init (void); /* 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 /* RTADV */ #endif /* _ZEBRA_RTADV_H */ quagga-0.99.22.4/zebra/rtread_getmsg.c0000644000175000017500000001415512132522417014330 00000000000000/* * Kernel routing table readup by getmsg(2) * Copyright (C) 1999 Michael Handler * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "log.h" #include "if.h" #include "zebra/rib.h" #include "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, 0, 0, 0, SAFI_UNICAST); } void route_read (void) { char storage[RT_BUFSIZ]; struct T_optmgmt_req *TLIreq = (struct T_optmgmt_req *) storage; struct T_optmgmt_ack *TLIack = (struct T_optmgmt_ack *) storage; struct T_error_ack *TLIerr = (struct T_error_ack *) storage; struct opthdr *MIB2hdr; mib2_ipRouteEntry_t *routeEntry, *lastRouteEntry; struct strbuf msgdata; int flags, dev, retval, process; if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, 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 && msgdata.len >= sizeof (struct T_optmgmt_ack) && TLIack->PRIM_type == T_OPTMGMT_ACK && TLIack->MGMT_flags == T_SUCCESS && MIB2hdr->len == 0) break; if (msgdata.len >= sizeof (struct T_error_ack) && TLIerr->PRIM_type == T_ERROR_ACK) { zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", 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 || 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-0.99.22.4/zebra/rtread_netlink.c0000644000175000017500000000173312132522417014504 00000000000000/* * 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" extern void netlink_route_read (void); void route_read (void) { netlink_route_read (); } quagga-0.99.22.4/zebra/rtread_proc.c0000644000175000017500000001064512132522417014005 00000000000000/* * Kernel routing readup by /proc filesystem * Copyright (C) 1997 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "log.h" #include "if.h" #include "rib.h" #include "zebra/zserv.h" #include "zebra/rt.h" /* Proc file system to read IPv4 routing table. */ #ifndef _PATH_PROCNET_ROUTE #define _PATH_PROCNET_ROUTE "/proc/net/route" #endif /* _PATH_PROCNET_ROUTE */ /* Proc file system to read IPv6 routing table. */ #ifndef _PATH_PROCNET_ROUTE6 #define _PATH_PROCNET_ROUTE6 "/proc/net/ipv6_route" #endif /* _PATH_PROCNET_ROUTE6 */ /* To read interface's name */ #define INTERFACE_NAMSIZ 20 /* Reading buffer for one routing entry. */ #define RT_BUFSIZ 1024 /* Kernel routing table read up by /proc filesystem. */ static int proc_route_read (void) { FILE *fp; char buf[RT_BUFSIZ]; char iface[INTERFACE_NAMSIZ], dest[9], gate[9], mask[9]; int flags, refcnt, use, metric, mtu, window, rtt; /* Open /proc filesystem */ fp = fopen (_PATH_PROCNET_ROUTE, "r"); if (fp == NULL) { zlog_warn ("Can't open %s : %s\n", _PATH_PROCNET_ROUTE, safe_strerror (errno)); return -1; } /* Drop first label line. */ fgets (buf, RT_BUFSIZ, fp); while (fgets (buf, RT_BUFSIZ, fp) != NULL) { int n; struct prefix_ipv4 p; struct in_addr tmpmask; struct in_addr gateway; u_char zebra_flags = 0; n = sscanf (buf, "%s %s %s %x %d %d %d %s %d %d %d", iface, dest, gate, &flags, &refcnt, &use, &metric, mask, &mtu, &window, &rtt); if (n != 11) { zlog_warn ("can't read all of routing information\n"); continue; } if (! (flags & RTF_UP)) continue; if (! (flags & RTF_GATEWAY)) continue; if (flags & RTF_DYNAMIC) zebra_flags |= ZEBRA_FLAG_SELFROUTE; p.family = AF_INET; sscanf (dest, "%lX", (unsigned long *)&p.prefix); sscanf (mask, "%lX", (unsigned long *)&tmpmask); p.prefixlen = ip_masklen (tmpmask); sscanf (gate, "%lX", (unsigned long *)&gateway); rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST); } fclose (fp); return 0; } #ifdef HAVE_IPV6 static int proc_ipv6_route_read () { FILE *fp; char buf [RT_BUFSIZ]; /* Open /proc filesystem */ fp = fopen (_PATH_PROCNET_ROUTE6, "r"); if (fp == NULL) { zlog_warn ("Can't open %s : %s", _PATH_PROCNET_ROUTE6, safe_strerror (errno)); return -1; } /* There is no title line, so we don't drop first line. */ while (fgets (buf, RT_BUFSIZ, fp) != NULL) { int n; char dest[33], src[33], gate[33]; char iface[INTERFACE_NAMSIZ]; int dest_plen, src_plen; int metric, use, refcnt, flags; struct prefix_ipv6 p; struct in6_addr gateway; u_char zebra_flags = 0; /* Linux 2.1.x write this information at net/ipv6/route.c rt6_info_node () */ n = sscanf (buf, "%32s %02x %32s %02x %32s %08x %08x %08x %08x %s", dest, &dest_plen, src, &src_plen, gate, &metric, &use, &refcnt, &flags, iface); if (n != 10) { /* zlog_warn ("can't read all of routing information %d\n%s\n", n, buf); */ continue; } if (! (flags & RTF_UP)) continue; if (! (flags & RTF_GATEWAY)) continue; if (flags & RTF_DYNAMIC) zebra_flags |= ZEBRA_FLAG_SELFROUTE; p.family = AF_INET6; str2in6_addr (dest, &p.prefix); str2in6_addr (gate, &gateway); p.prefixlen = dest_plen; rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gateway, 0, 0, metric, 0); } fclose (fp); return 0; } #endif /* HAVE_IPV6 */ void route_read (void) { proc_route_read (); #ifdef HAVE_IPV6 proc_ipv6_route_read (); #endif /* HAVE_IPV6 */ } quagga-0.99.22.4/zebra/rtread_sysctl.c0000644000175000017500000000376412132522417014367 00000000000000/* * 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 "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" /* Kernel routing table read up by sysctl function. */ void route_read (void) { 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 }; /* 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-0.99.22.4/zebra/test_main.c0000644000175000017500000001627212177450262013475 00000000000000/* 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 "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 unsigned int 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, }, }; /* Main startup routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = 0; int batch_mode = 0; int daemon_mode = 0; char *config_file = NULL; char *progname; struct thread thread; /* 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 (); if_init(); zebra_debug_init (); zebra_if_init (); test_cmd_init (); /* Zebra related initialize. */ rib_init (); access_list_init (); /* Make kernel routing socket. */ kernel_init (); route_read (); zebra_vty_init(); /* Sort VTY commands. */ sort_node (); /* 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); while (thread_fetch (zebrad.master, &thread)) thread_call (&thread); /* Not reached... */ return 0; } quagga-0.99.22.4/zebra/zebra.conf.sample0000644000175000017500000000056112000052240014545 00000000000000! -*- 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-0.99.22.4/zebra/zebra_fpm.c0000644000175000017500000007717612177450262013471 00000000000000/* * 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; /* * Globals. */ typedef struct zfpm_glob_t_ { /* * True if the FPM module has been enabled. */ int enabled; struct thread_master *master; zfpm_state_t state; /* * 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->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) { #ifndef HAVE_NETLINK return 0; #else int cmd; cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE; return zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len); #endif /* HAVE_NETLINK */ } /* * zfpm_route_for_update * * Returns the rib that is to be sent to the FPM for a given dest. */ static struct rib * zfpm_route_for_update (rib_dest_t *dest) { struct rib *rib; RIB_DEST_FOREACH_ROUTE (dest, rib) { if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) 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; 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; hdr->msg_type = FPM_MSG_TYPE_NETLINK; 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); assert (data_len); if (data_len) { 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 */ serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); /* * 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[INET6_ADDRSTRLEN]; /* * 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/%d triggering update to FPM - Reason: %s", inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)), rn->p.prefixlen, 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; } /** * 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 * * Returns TRUE on success. */ int zfpm_init (struct thread_master *master, int enable, uint16_t port) { 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; /* * Netlink must currently be available for the Zebra-FPM interface * to be enabled. */ #ifndef HAVE_NETLINK enable = 0; #endif zfpm_g->enabled = enable; 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); if (!enable) { return 1; } 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-0.99.22.4/zebra/zebra_fpm.h0000644000175000017500000000224112177450262013453 00000000000000/* * 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); extern void zfpm_trigger_update (struct route_node *rn, const char *reason); #endif /* _ZEBRA_FPM_H */ quagga-0.99.22.4/zebra/zebra_fpm_netlink.c0000644000175000017500000002724412177450262015204 00000000000000/* * 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 "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. We keep things simple for now by enforcing a * maximum of 64 in case MULTIPATH_NUM is 0; */ netlink_nh_info_t nhs[MAX (MULTIPATH_NUM, 64)]; 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) { 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; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { nhi.recursive = 1; nhi.type = nexthop->rtype; nhi.if_index = nexthop->rifindex; if (nexthop->rtype == NEXTHOP_TYPE_IPV4 || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX) { nhi.gateway = &nexthop->rgate; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } #ifdef HAVE_IPV6 if (nexthop->rtype == NEXTHOP_TYPE_IPV6 || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME) { nhi.gateway = &nexthop->rgate; } #endif /* HAVE_IPV6 */ if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX || nexthop->rtype == NEXTHOP_TYPE_IFNAME) { if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } goto done; } nhi.recursive = 0; 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; } /* * Fall through... */ done: 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 = NULL; 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)->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 && !rib) goto skip; if (rib) 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; } /* Multipath case. */ if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1) { for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { netlink_route_info_add_nh (ri, nexthop); break; } } } else { for (nexthop = rib->nexthop; nexthop && (MULTIPATH_NUM == 0 || ri->num_nhs < MULTIPATH_NUM); nexthop = nexthop->next) { if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { netlink_route_info_add_nh (ri, nexthop); } } } /* 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) { int 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-0.99.22.4/zebra/zebra_fpm_private.h0000644000175000017500000000310112177450262015201 00000000000000/* * 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); #endif /* _ZEBRA_FPM_PRIVATE_H */ quagga-0.99.22.4/zebra/zebra_rib.c0000644000175000017500000023637312211105060013435 00000000000000/* 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 "zebra/rib.h" #include "zebra/rt.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/zebra_fpm.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}, /* no entry/default: 150 */ }; /* Vector for routing table. */ static vector vrf_vector; /* * vrf_table_create */ static void vrf_table_create (struct vrf *vrf, afi_t afi, safi_t safi) { rib_table_info_t *info; struct route_table *table; assert (!vrf->table[afi][safi]); table = route_table_init (); vrf->table[afi][safi] = table; info = XCALLOC (MTYPE_RIB_TABLE_INFO, sizeof (*info)); info->vrf = vrf; info->afi = afi; info->safi = safi; table->info = info; } /* Allocate new VRF. */ static struct vrf * vrf_alloc (const char *name) { struct vrf *vrf; vrf = XCALLOC (MTYPE_VRF, sizeof (struct vrf)); /* Put name. */ if (name) vrf->name = XSTRDUP (MTYPE_VRF_NAME, name); /* Allocate routing table and static table. */ vrf_table_create (vrf, AFI_IP, SAFI_UNICAST); vrf_table_create (vrf, AFI_IP6, SAFI_UNICAST); vrf->stable[AFI_IP][SAFI_UNICAST] = route_table_init (); vrf->stable[AFI_IP6][SAFI_UNICAST] = route_table_init (); vrf_table_create (vrf, AFI_IP, SAFI_MULTICAST); vrf_table_create (vrf, AFI_IP6, SAFI_MULTICAST); vrf->stable[AFI_IP][SAFI_MULTICAST] = route_table_init (); vrf->stable[AFI_IP6][SAFI_MULTICAST] = route_table_init (); return vrf; } /* Lookup VRF by identifier. */ struct vrf * vrf_lookup (u_int32_t id) { return vector_lookup (vrf_vector, id); } /* Initialize VRF. */ static void vrf_init (void) { struct vrf *default_table; /* Allocate VRF vector. */ vrf_vector = vector_init (1); /* Allocate default main table. */ default_table = vrf_alloc ("Default-IP-Routing-Table"); /* Default table index must be 0. */ vector_set_index (vrf_vector, 0, default_table); } /* Lookup route table. */ struct route_table * vrf_table (afi_t afi, safi_t safi, u_int32_t id) { struct vrf *vrf; vrf = vrf_lookup (id); if (! vrf) return NULL; if( afi >= AFI_MAX || safi >= SAFI_MAX ) return NULL; return vrf->table[afi][safi]; } /* Lookup static route table. */ struct route_table * vrf_static_table (afi_t afi, safi_t safi, u_int32_t id) { struct vrf *vrf; vrf = vrf_lookup (id); if (! vrf) return NULL; if( afi >= AFI_MAX || safi >= SAFI_MAX ) return NULL; return vrf->stable[afi][safi]; } /* * 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]; } /* Add nexthop to the end of the list. */ static void nexthop_add (struct rib *rib, struct nexthop *nexthop) { struct nexthop *last; for (last = rib->nexthop; last && last->next; last = last->next) ; if (last) last->next = nexthop; else rib->nexthop = nexthop; nexthop->prev = last; rib->nexthop_num++; } /* Delete specified nexthop from the list. */ static void nexthop_delete (struct rib *rib, struct nexthop *nexthop) { if (nexthop->next) nexthop->next->prev = nexthop->prev; if (nexthop->prev) nexthop->prev->next = nexthop->next; else rib->nexthop = nexthop->next; rib->nexthop_num--; } /* Free nexthop. */ static void nexthop_free (struct nexthop *nexthop) { if (nexthop->ifname) XFREE (0, nexthop->ifname); XFREE (MTYPE_NEXTHOP, nexthop); } struct nexthop * nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IFINDEX; nexthop->ifindex = ifindex; nexthop_add (rib, nexthop); return nexthop; } struct nexthop * nexthop_ifname_add (struct rib *rib, char *ifname) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IFNAME; nexthop->ifname = XSTRDUP (0, ifname); nexthop_add (rib, nexthop); return nexthop; } struct nexthop * nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV4; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; nexthop_add (rib, nexthop); return nexthop; } struct nexthop * nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src, unsigned int ifindex) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nexthop->gate.ipv4 = *ipv4; if (src) nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; nexthop_add (rib, nexthop); return nexthop; } #ifdef HAVE_IPV6 struct nexthop * nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV6; nexthop->gate.ipv6 = *ipv6; nexthop_add (rib, nexthop); return nexthop; } static struct nexthop * nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, char *ifname) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; nexthop->gate.ipv6 = *ipv6; nexthop->ifname = XSTRDUP (0, ifname); nexthop_add (rib, nexthop); return nexthop; } static struct nexthop * nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, unsigned int ifindex) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; nexthop->gate.ipv6 = *ipv6; nexthop->ifindex = ifindex; nexthop_add (rib, nexthop); return nexthop; } #endif /* HAVE_IPV6 */ struct nexthop * nexthop_blackhole_add (struct rib *rib) { struct nexthop *nexthop; nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); nexthop_add (rib, nexthop); return nexthop; } /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ 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; struct nexthop *newhop; if (nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = 0; if (set) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = nexthop->gate.ipv4; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return 0; rn = route_node_match (table, (struct prefix *) &p); while (rn) { route_unlock_node (rn); /* If lookup self prefix return 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->flags, ZEBRA_FLAG_SELECTED)) break; } /* If there is no selected route or matched route is EGP, go up tree. */ if (! match || match->type == ZEBRA_ROUTE_BGP) { do { rn = rn->parent; } while (rn && rn->info == NULL); if (rn) route_lock_node (rn); } else { if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ newhop = match->nexthop; if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4) nexthop->ifindex = newhop->ifindex; return 1; } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthop->rtype = newhop->type; if (newhop->type == NEXTHOP_TYPE_IPV4 || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) nexthop->rgate.ipv4 = newhop->gate.ipv4; if (newhop->type == NEXTHOP_TYPE_IFINDEX || newhop->type == NEXTHOP_TYPE_IFNAME || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) nexthop->rifindex = newhop->ifindex; } return 1; } return 0; } else { return 0; } } } return 0; } #ifdef HAVE_IPV6 /* If force flag is not set, do not modify falgs at all for uninstall the route from FIB. */ 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; struct nexthop *newhop; if (nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = 0; if (set) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); /* Make lookup prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = IPV6_MAX_PREFIXLEN; p.prefix = nexthop->gate.ipv6; /* Lookup table. */ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return 0; rn = route_node_match (table, (struct prefix *) &p); while (rn) { route_unlock_node (rn); /* If lookup self prefix return 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->flags, ZEBRA_FLAG_SELECTED)) break; } /* If there is no selected route or matched route is EGP, go up tree. */ if (! match || match->type == ZEBRA_ROUTE_BGP) { do { rn = rn->parent; } while (rn && rn->info == NULL); if (rn) route_lock_node (rn); } else { if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ newhop = match->nexthop; if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6) nexthop->ifindex = newhop->ifindex; return 1; } else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (set) { SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); nexthop->rtype = newhop->type; if (newhop->type == NEXTHOP_TYPE_IPV6 || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) nexthop->rgate.ipv6 = newhop->gate.ipv6; if (newhop->type == NEXTHOP_TYPE_IFINDEX || newhop->type == NEXTHOP_TYPE_IFNAME || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) nexthop->rifindex = newhop->ifindex; } return 1; } return 0; } else { return 0; } } } return 0; } #endif /* HAVE_IPV6 */ struct rib * rib_match_ipv4 (struct in_addr addr) { struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *newhop; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return 0; memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = addr; rn = route_node_match (table, (struct prefix *) &p); while (rn) { route_unlock_node (rn); /* Pick up selected route. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) break; } /* If there is no selected route or matched route is EGP, go up tree. */ if (! match || match->type == ZEBRA_ROUTE_BGP) { do { rn = rn->parent; } while (rn && rn->info == NULL); if (rn) route_lock_node (rn); } else { if (match->type == ZEBRA_ROUTE_CONNECT) /* Directly point connected route. */ return match; else { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) return match; return NULL; } } } return NULL; } struct rib * rib_lookup_ipv4 (struct prefix_ipv4 *p) { struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *nexthop; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return 0; rn = route_node_lookup (table, (struct prefix *) p); /* No route for this prefix. */ if (! rn) return NULL; /* Unlock node. */ route_unlock_node (rn); RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) break; } if (! match || match->type == ZEBRA_ROUTE_BGP) return NULL; if (match->type == ZEBRA_ROUTE_CONNECT) return match; for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) return match; return NULL; } /* * 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) { struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *nexthop; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return 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->flags, ZEBRA_FLAG_SELECTED)) 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... */ for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { /* We are happy with either direct or recursive hexthop */ if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) || nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate)) return ZEBRA_RIB_FOUND_EXACT; else { if (IS_ZEBRA_DEBUG_RIB) { char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN); inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN); zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); } return ZEBRA_RIB_FOUND_NOGATE; } } return ZEBRA_RIB_NOTFOUND; } #ifdef HAVE_IPV6 struct rib * rib_match_ipv6 (struct in6_addr *addr) { struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; struct rib *match; struct nexthop *newhop; /* Lookup table. */ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return 0; memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = IPV6_MAX_PREFIXLEN; IPV6_ADDR_COPY (&p.prefix, addr); rn = route_node_match (table, (struct prefix *) &p); while (rn) { route_unlock_node (rn); /* Pick up selected route. */ RNODE_FOREACH_RIB (rn, match) { if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) continue; if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) break; } /* If there is no selected route or matched route is EGP, go up tree. */ if (! match || match->type == ZEBRA_ROUTE_BGP) { do { rn = rn->parent; } while (rn && rn->info == NULL); if (rn) route_lock_node (rn); } else { if (match->type == ZEBRA_ROUTE_CONNECT) /* Directly point connected route. */ return match; else { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) return match; return NULL; } } } return NULL; } #endif /* HAVE_IPV6 */ #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) { 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 (nexthop->ifindex); 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 (nexthop->ifname); 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; #ifdef HAVE_IPV6 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 (nexthop->ifindex); 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; #endif /* HAVE_IPV6 */ case NEXTHOP_TYPE_BLACKHOLE: SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) return 0; 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); 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) { ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop); } 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 ZEBRA_FLAG_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, prev_index, new_active; rib->nexthop_active_num = 0; UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); 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->flags, ZEBRA_FLAG_CHANGED); } return rib->nexthop_active_num; } static void rib_install_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; struct nexthop *nexthop; /* * Make sure we update the FPM any time we send new information to * the kernel. */ zfpm_trigger_update (rn, "installing in kernel"); switch (PREFIX_FAMILY (&rn->p)) { case AF_INET: ret = kernel_add_ipv4 (&rn->p, rib); break; #ifdef HAVE_IPV6 case AF_INET6: ret = kernel_add_ipv6 (&rn->p, rib); break; #endif /* HAVE_IPV6 */ } /* This condition is never met, if we are using rt_socket.c */ if (ret < 0) { for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } } /* Uninstall the route from kernel. */ static int rib_uninstall_kernel (struct route_node *rn, struct rib *rib) { int ret = 0; struct nexthop *nexthop; /* * Make sure we update the FPM any time we send new information to * the kernel. */ zfpm_trigger_update (rn, "uninstalling from kernel"); switch (PREFIX_FAMILY (&rn->p)) { case AF_INET: ret = kernel_delete_ipv4 (&rn->p, rib); break; #ifdef HAVE_IPV6 case AF_INET6: ret = kernel_delete_ipv6 (&rn->p, rib); break; #endif /* HAVE_IPV6 */ } for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); return ret; } /* Uninstall the route from kernel. */ static void rib_uninstall (struct route_node *rn, struct rib *rib) { if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { zfpm_trigger_update (rn, "rib_uninstall"); redistribute_delete (&rn->p, rib); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); 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; char buf[INET6_ADDRSTRLEN]; dest = rib_dest_from_rnode (rn); if (!dest) return 0; if (!rib_can_delete_dest (dest)) return 0; if (IS_ZEBRA_DEBUG_RIB) { inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)); zlog_debug ("%s: %s/%d: removing dest from table", __func__, buf, rn->p.prefixlen); } 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; } /* Core function for processing routing information base. */ static void rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; struct rib *fib = NULL; struct rib *select = NULL; struct rib *del = NULL; int installed = 0; struct nexthop *nexthop = NULL; char buf[INET6_ADDRSTRLEN]; assert (rn); if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); RNODE_FOREACH_RIB_SAFE (rn, rib, next) { /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) { assert (fib == NULL); fib = rib; } /* Unlock removed routes, so they'll be freed, bar the FIB entry, * which we need to do do further work with below. */ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (rib != fib) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, buf, rn->p.prefixlen, rn, rib); rib_unlink (rn, rib); } else del = rib; continue; } /* Skip unreachable nexthop. */ if (! nexthop_active_update (rn, rib, 0)) continue; /* Infinit distance. */ if (rib->distance == DISTANCE_INFINITY) continue; /* Newly selected rib, the common case. */ if (!select) { select = rib; continue; } /* 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 (rib->type == ZEBRA_ROUTE_CONNECT) { if (select->type != ZEBRA_ROUTE_CONNECT || rib->metric <= select->metric) select = rib; continue; } else if (select->type == ZEBRA_ROUTE_CONNECT) continue; /* higher distance loses */ if (rib->distance > select->distance) continue; /* lower wins */ if (rib->distance < select->distance) { select = rib; continue; } /* metric tie-breaks equal distance */ if (rib->metric <= select->metric) select = rib; } /* RNODE_FOREACH_RIB_SAFE */ /* After the cycle is finished, the following pointers will be set: * select --- the winner RIB entry, if any was found, otherwise NULL * fib --- the SELECTED RIB entry, if any, otherwise NULL * del --- equal to fib, if fib is queued for deletion, NULL otherwise * rib --- NULL */ /* Same RIB entry is selected. Update FIB and finish. */ if (select && select == fib) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", __func__, buf, rn->p.prefixlen, select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { zfpm_trigger_update (rn, "updating existing route"); redistribute_delete (&rn->p, select); if (! RIB_SYSTEM_ROUTE (select)) rib_uninstall_kernel (rn, select); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); if (! RIB_SYSTEM_ROUTE (select)) rib_install_kernel (rn, select); redistribute_add (&rn->p, select); } else if (! RIB_SYSTEM_ROUTE (select)) { /* 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 the routes are IN the kernel. */ for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { installed = 1; break; } if (! installed) rib_install_kernel (rn, select); } goto end; } /* At this point we either haven't found the best RIB entry or it is * different from what we currently intend to flag with SELECTED. In both * cases, if a RIB block is present in FIB, it should be withdrawn. */ if (fib) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, buf, rn->p.prefixlen, fib); zfpm_trigger_update (rn, "removing existing route"); redistribute_delete (&rn->p, fib); if (! RIB_SYSTEM_ROUTE (fib)) rib_uninstall_kernel (rn, fib); UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); /* Set real nexthop. */ nexthop_active_update (rn, fib, 1); } /* Regardless of some RIB entry being SELECTED or not before, now we can * tell, that if a new winner exists, FIB is still not updated with this * data, but ready to be. */ if (select) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, rn->p.prefixlen, select); zfpm_trigger_update (rn, "new route selected"); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); if (! RIB_SYSTEM_ROUTE (select)) rib_install_kernel (rn, select); SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); redistribute_add (&rn->p, select); } /* FIB route was removed, should be deleted */ if (del) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf, rn->p.prefixlen, del, rn); rib_unlink (rn, del); } end: if (IS_ZEBRA_DEBUG_RIB_Q) zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, 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; } /* 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, }; /* 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; char buf[INET6_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_RIB_Q) inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); 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) zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", __func__, buf, rn->p.prefixlen, 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) zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", __func__, buf, rn->p.prefixlen, rn, qindex); } } /* Add route_node to work queue and schedule processing */ static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { char buf[INET_ADDRSTRLEN]; assert (zebra && rn); if (IS_ZEBRA_DEBUG_RIB_Q) inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); /* 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__, rn, rn->lock); zlog_backtrace(LOG_DEBUG); return; } if (IS_ZEBRA_DEBUG_RIB_Q) zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); 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) zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, 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; /* 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_ipv{4,6} (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; char buf[INET6_ADDRSTRLEN]; assert (rib && rn); if (IS_ZEBRA_DEBUG_RIB) { inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, buf, rn->p.prefixlen, rn, rib); } dest = rib_dest_from_rnode (rn); if (!dest) { if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: %s/%d: adding dest to table", __func__, buf, rn->p.prefixlen); } 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) { char buf[INET6_ADDRSTRLEN]; inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", __func__, buf, rn->p.prefixlen, rn, 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) { struct nexthop *nexthop, *next; char buf[INET6_ADDRSTRLEN]; rib_dest_t *dest; assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) { inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, buf, rn->p.prefixlen, rn, 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 */ for (nexthop = rib->nexthop; nexthop; nexthop = next) { next = nexthop->next; nexthop_free (nexthop); } XFREE (MTYPE_RIB, rib); } static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) { char buf[INET6_ADDRSTRLEN]; inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, buf, rn->p.prefixlen, rn, 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, unsigned int ifindex, u_int32_t vrf_id, u_int32_t metric, 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 = vrf_table (AFI_IP, safi, 0); if (! table) return 0; /* Make it sure prefixlen is applied to the prefix. */ apply_mask_ipv4 (p); /* Set default distance by route type. */ if (distance == 0) { 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->table = vrf_id; rib->nexthop_num = 0; rib->uptime = time (NULL); /* Nexthop settings. */ if (gate) { if (ifindex) nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); else nexthop_ipv4_add (rib, gate, src); } else nexthop_ifindex_add (rib, ifindex); /* If this route is kernel route, set FIB flag to the route. */ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); /* Link new rib to node.*/ if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib); rib_addnode (rn, rib); /* Free implicit route.*/ if (same) { if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, rn, 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, const struct prefix_ipv4 * p, const struct rib * rib) { char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN]; struct nexthop *nexthop; inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN); zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen); 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 (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN); inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN); zlog_debug ( "%s: NH %s (%s) with flags %s%s%s", func, straddr1, straddr2, (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 = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) { zlog_err ("%s: vrf_table() returned NULL", __func__); return; } inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN); /* 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/%d", __func__, prefix_buf, p->prefixlen); 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__, rn, rib, (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") ); rib_dump (__func__, p, rib); } } /* Check if requested address assignment will fail due to another * route being installed by zebra in FIB already. Take necessary * actions, if needed: remove such a route from FIB and deSELECT * corresponding RIB entry. Then put affected RN into RIBQ head. */ void rib_lookup_and_pushup (struct prefix_ipv4 * p) { struct route_table *table; struct route_node *rn; struct rib *rib; unsigned changed = 0; if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0))) { zlog_err ("%s: vrf_table() returned NULL", __func__); return; } /* No matches would be the simplest case. */ if (NULL == (rn = route_node_lookup (table, (struct prefix *) p))) return; /* Unlock node. */ route_unlock_node (rn); /* Check all RIB entries. In case any changes have to be done, requeue * the RN into RIBQ head. If the routing message about the new connected * route (generated by the IP address we are going to assign very soon) * comes before the RIBQ is processed, the new RIB entry will join * RIBQ record already on head. This is necessary for proper revalidation * of the rest of the RIB. */ RNODE_FOREACH_RIB (rn, rib) { if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && ! RIB_SYSTEM_ROUTE (rib)) { changed = 1; if (IS_ZEBRA_DEBUG_RIB) { char buf[INET_ADDRSTRLEN]; inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib); } rib_uninstall (rn, rib); } } if (changed) rib_queue_add (&zebrad, rn); } 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; /* Lookup table. */ table = vrf_table (AFI_IP, safi, 0); if (! table) return 0; /* Make it sure prefixlen is applied to the prefix. */ apply_mask_ipv4 (p); /* Set default distance by route type. */ if (rib->distance == 0) { rib->distance = route_info[rib->type].distance; /* iBGP distance is 200. */ if (rib->type == ZEBRA_ROUTE_BGP && CHECK_FLAG (rib->flags, ZEBRA_FLAG_IBGP)) rib->distance = 200; } /* Lookup route node.*/ rn = route_node_get (table, (struct prefix *) p); /* If same type of route are installed, treat it as a implicit withdraw. */ 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); if (IS_ZEBRA_DEBUG_RIB) { zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", __func__, rn, rib); rib_dump (__func__, 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__, rn, same); rib_dump (__func__, p, same); } rib_delnode (rn, same); } route_unlock_node (rn); return 0; } /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct in_addr *gate, unsigned int ifindex, u_int32_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; char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; /* Lookup table. */ table = vrf_table (AFI_IP, safi, 0); if (! table) return 0; /* Apply mask. */ apply_mask_ipv4 (p); if (IS_ZEBRA_DEBUG_KERNEL && gate) zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, inet_ntoa (*gate), 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/%d via %s ifindex %d doesn't exist in rib", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex); else zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, 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->flags, ZEBRA_FLAG_SELECTED)) 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 || ((nexthop = rib->nexthop) && (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) { same = rib; break; } } /* If same type of route can't be found and this message is from kernel. */ if (! same) { if (fib && type == ZEBRA_ROUTE_KERNEL) { /* Unset flags. */ for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); } else { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, inet_ntop (AF_INET, gate, buf2, INET_ADDRSTRLEN), ifindex, type); else zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), p->prefixlen, 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_ipv4 (struct prefix *p, struct static_ipv4 *si) { struct rib *rib; struct route_node *rn; struct route_table *table; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return; /* Lookup existing route */ rn = route_node_get (table, p); 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) { /* Same distance static route is there. Update it with new nexthop. */ route_unlock_node (rn); switch (si->type) { case STATIC_IPV4_GATEWAY: nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); break; case STATIC_IPV4_IFNAME: nexthop_ifname_add (rib, si->gate.ifname); break; case STATIC_IPV4_BLACKHOLE: nexthop_blackhole_add (rib); 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->table = zebrad.rtm_table_default; rib->nexthop_num = 0; switch (si->type) { case STATIC_IPV4_GATEWAY: nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); break; case STATIC_IPV4_IFNAME: nexthop_ifname_add (rib, si->gate.ifname); break; case STATIC_IPV4_BLACKHOLE: nexthop_blackhole_add (rib); 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_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) { if (nexthop->type == NEXTHOP_TYPE_IPV4 && si->type == STATIC_IPV4_GATEWAY && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4)) return 1; if (nexthop->type == NEXTHOP_TYPE_IFNAME && si->type == STATIC_IPV4_IFNAME && strcmp (nexthop->ifname, si->gate.ifname) == 0) return 1; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE && si->type == STATIC_IPV4_BLACKHOLE) return 1; return 0; } /* Uninstall static route from RIB. */ static void static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) { struct route_node *rn; struct rib *rib; struct nexthop *nexthop; struct route_table *table; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return; /* Lookup existing route with type and distance. */ rn = route_node_lookup (table, p); if (! rn) return; 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) { route_unlock_node (rn); return; } /* Lookup nexthop. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (static_ipv4_nexthop_same (nexthop, si)) break; /* Can't find nexthop. */ if (! nexthop) { route_unlock_node (rn); return; } /* Check nexthop. */ if (rib->nexthop_num == 1) rib_delnode (rn, rib); else { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); nexthop_delete (rib, nexthop); nexthop_free (nexthop); rib_queue_add (&zebrad, rn); } /* Unlock node. */ route_unlock_node (rn); } /* Add static route into static route configuration. */ int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, u_char flags, u_char distance, u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; struct static_ipv4 *si; struct static_ipv4 *pp; struct static_ipv4 *cp; struct static_ipv4 *update = NULL; struct route_table *stable; /* Lookup table. */ stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! stable) return -1; /* Lookup static route prefix. */ rn = route_node_get (stable, p); /* Make flags. */ if (gate) type = STATIC_IPV4_GATEWAY; else if (ifname) type = STATIC_IPV4_IFNAME; else type = STATIC_IPV4_BLACKHOLE; /* Do nothing if there is a same static route. */ for (si = rn->info; si; si = si->next) { if (type == si->type && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) { if (distance == si->distance) { route_unlock_node (rn); return 0; } else update = si; } } /* Distance changed. */ if (update) static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); si->type = type; si->distance = distance; si->flags = flags; if (gate) si->gate.ipv4 = *gate; if (ifname) si->gate.ifname = XSTRDUP (0, ifname); /* Add new static route information to the tree with sort by distance value and gateway address. */ for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) { if (si->distance < cp->distance) break; if (si->distance > cp->distance) continue; if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) { if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr)) break; if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr)) continue; } } /* Make linked list. */ if (pp) pp->next = si; else rn->info = si; if (cp) cp->prev = si; si->prev = pp; si->next = cp; /* Install into rib. */ static_install_ipv4 (p, si); return 1; } /* Delete static route from static route configuration. */ int static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, u_char distance, u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; struct static_ipv4 *si; struct route_table *stable; /* Lookup table. */ stable = vrf_static_table (AFI_IP, SAFI_UNICAST, vrf_id); if (! stable) return -1; /* Lookup static route prefix. */ rn = route_node_lookup (stable, p); if (! rn) return 0; /* Make flags. */ if (gate) type = STATIC_IPV4_GATEWAY; else if (ifname) type = STATIC_IPV4_IFNAME; else type = STATIC_IPV4_BLACKHOLE; /* Find same static route is the tree */ for (si = rn->info; si; si = si->next) if (type == si->type && (! gate || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) break; /* Can't find static route. */ if (! si) { route_unlock_node (rn); return 0; } /* Install into rib. */ static_uninstall_ipv4 (p, si); /* Unlink static route from linked list. */ if (si->prev) si->prev->next = si->next; else rn->info = si->next; if (si->next) si->next->prev = si->prev; route_unlock_node (rn); /* Free static route configuration. */ if (ifname) XFREE (0, si->gate.ifname); XFREE (MTYPE_STATIC_IPV4, si); route_unlock_node (rn); return 1; } #ifdef HAVE_IPV6 static int rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, int table) { if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) { #if defined (MUSICA) || defined (LINUX) /* IN6_IS_ADDR_V4COMPAT(&p->prefix) */ if (p->prefixlen == 96) return 0; #endif /* MUSICA */ return 1; } if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate)) { kernel_delete_ipv6_old (p, gate, ifindex, 0, table); return 1; } return 0; } int rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_t vrf_id, u_int32_t metric, 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 = vrf_table (AFI_IP6, safi, 0); 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; /* Filter bogus route. */ if (rib_bogus_ipv6 (type, p, gate, ifindex, 0)) return 0; /* Lookup route node.*/ rn = route_node_get (table, (struct prefix *) p); /* If same type of route are installed, treat it as a implicit withdraw. */ 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->table = vrf_id; rib->nexthop_num = 0; rib->uptime = time (NULL); /* Nexthop settings. */ if (gate) { if (ifindex) nexthop_ipv6_ifindex_add (rib, gate, ifindex); else nexthop_ipv6_add (rib, gate); } else nexthop_ifindex_add (rib, ifindex); /* If this route is kernel route, set FIB flag to the route. */ if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); /* Link new rib to node.*/ rib_addnode (rn, rib); /* Free implicit route.*/ if (same) rib_delnode (rn, same); route_unlock_node (rn); return 0; } /* XXX factor with rib_delete_ipv6 */ int rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct in6_addr *gate, unsigned int ifindex, u_int32_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; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; /* Apply mask. */ apply_mask_ipv6 (p); /* Lookup table. */ table = vrf_table (AFI_IP6, safi, 0); if (! table) return 0; /* Lookup route node. */ rn = route_node_lookup (table, (struct prefix *) p); if (! rn) { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("route %s/%d via %s ifindex %d doesn't exist in rib", inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex); else zlog_debug ("route %s/%d ifindex %d doesn't exist in rib", inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, 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->flags, ZEBRA_FLAG_SELECTED)) 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 || ((nexthop = rib->nexthop) && (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)))) { same = rib; break; } } /* If same type of route can't be found and this message is from kernel. */ if (! same) { if (fib && type == ZEBRA_ROUTE_KERNEL) { /* Unset flags. */ for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); } else { if (IS_ZEBRA_DEBUG_KERNEL) { if (gate) zlog_debug ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, inet_ntop (AF_INET6, gate, buf2, INET6_ADDRSTRLEN), ifindex, type); else zlog_debug ("route %s/%d ifindex %d type %d doesn't exist in rib", inet_ntop (AF_INET6, &p->prefix, buf1, INET6_ADDRSTRLEN), p->prefixlen, 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_ipv6 (struct prefix *p, struct static_ipv6 *si) { struct rib *rib; struct route_table *table; struct route_node *rn; /* Lookup table. */ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return; /* Lookup existing route */ rn = route_node_get (table, p); 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) { /* Same distance static route is there. Update it with new nexthop. */ route_unlock_node (rn); switch (si->type) { case STATIC_IPV6_GATEWAY: nexthop_ipv6_add (rib, &si->ipv6); break; case STATIC_IPV6_IFNAME: nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; } 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->nexthop_num = 0; switch (si->type) { case STATIC_IPV6_GATEWAY: nexthop_ipv6_add (rib, &si->ipv6); break; case STATIC_IPV6_IFNAME: nexthop_ifname_add (rib, si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; } /* 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_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) { if (nexthop->type == NEXTHOP_TYPE_IPV6 && si->type == STATIC_IPV6_GATEWAY && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)) return 1; if (nexthop->type == NEXTHOP_TYPE_IFNAME && si->type == STATIC_IPV6_IFNAME && strcmp (nexthop->ifname, si->ifname) == 0) return 1; if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME && si->type == STATIC_IPV6_GATEWAY_IFNAME && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) && strcmp (nexthop->ifname, si->ifname) == 0) return 1; return 0; } static void static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) { struct route_table *table; struct route_node *rn; struct rib *rib; struct nexthop *nexthop; /* Lookup table. */ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return; /* Lookup existing route with type and distance. */ rn = route_node_lookup (table, (struct prefix *) p); if (! rn) return; 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) { route_unlock_node (rn); return; } /* Lookup nexthop. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) if (static_ipv6_nexthop_same (nexthop, si)) break; /* Can't find nexthop. */ if (! nexthop) { route_unlock_node (rn); return; } /* Check nexthop. */ if (rib->nexthop_num == 1) { rib_delnode (rn, rib); } else { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); nexthop_delete (rib, nexthop); nexthop_free (nexthop); rib_queue_add (&zebrad, rn); } /* Unlock node. */ route_unlock_node (rn); } /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char flags, u_char distance, u_int32_t vrf_id) { struct route_node *rn; struct static_ipv6 *si; struct static_ipv6 *pp; struct static_ipv6 *cp; struct route_table *stable; /* Lookup table. */ stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! stable) return -1; 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 (distance == si->distance && type == si->type && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) { route_unlock_node (rn); return 0; } } /* Make new static route structure. */ si = XCALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6)); si->type = type; si->distance = distance; si->flags = flags; switch (type) { case STATIC_IPV6_GATEWAY: si->ipv6 = *gate; break; case STATIC_IPV6_IFNAME: si->ifname = XSTRDUP (0, ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: si->ipv6 = *gate; si->ifname = XSTRDUP (0, ifname); break; } /* Add new static route information to the tree with sort by distance value and gateway address. */ for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) { if (si->distance < cp->distance) break; if (si->distance > cp->distance) continue; } /* Make linked list. */ if (pp) pp->next = si; else rn->info = si; if (cp) cp->prev = si; si->prev = pp; si->next = cp; /* Install into rib. */ static_install_ipv6 (p, si); return 1; } /* Delete static route from static route configuration. */ int static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, const char *ifname, u_char distance, u_int32_t vrf_id) { struct route_node *rn; struct static_ipv6 *si; struct route_table *stable; /* Lookup table. */ stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! stable) return -1; /* Lookup static route prefix. */ rn = route_node_lookup (stable, p); if (! rn) return 0; /* Find same static route is the tree */ for (si = rn->info; si; si = si->next) if (distance == si->distance && type == si->type && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) && (! ifname || strcmp (ifname, si->ifname) == 0)) break; /* Can't find static route. */ if (! si) { route_unlock_node (rn); return 0; } /* Install into rib. */ static_uninstall_ipv6 (p, si); /* Unlink static route from linked list. */ if (si->prev) si->prev->next = si->next; else rn->info = si->next; if (si->next) si->next->prev = si->prev; /* Free static route configuration. */ if (ifname) XFREE (0, si->ifname); XFREE (MTYPE_STATIC_IPV6, si); return 1; } #endif /* HAVE_IPV6 */ /* RIB update function. */ void rib_update (void) { struct route_node *rn; struct route_table *table; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rnode_to_ribs (rn)) rib_queue_add (&zebrad, rn); table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); 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) { rib_weed_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_weed_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } /* Delete self installed routes after zebra is relaunched. */ 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_uninstall_kernel (rn, rib); if (! ret) rib_delnode (rn, rib); } } } /* Sweep all RIB tables. */ void rib_sweep_route (void) { rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } /* 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) { return rib_score_proto_table (proto, vrf_table (AFI_IP, SAFI_UNICAST, 0)) +rib_score_proto_table (proto, vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } /* Close RIB and clean up kernel routes. */ static void rib_close_table (struct route_table *table) { struct route_node *rn; struct rib *rib; if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) continue; zfpm_trigger_update (rn, NULL); if (! RIB_SYSTEM_ROUTE (rib)) rib_uninstall_kernel (rn, rib); } } /* Close all RIB tables. */ void rib_close (void) { rib_close_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_close_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } /* Routing information base initialize. */ void rib_init (void) { rib_queue_init (&zebrad); /* VRF initialization. */ vrf_init (); } /* * 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 (uint32_t id, uint32_t *next_id_p) { while (++id < vector_active (vrf_vector)) { if (vrf_lookup (id)) { *next_id_p = 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 = 0; 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 = 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; } quagga-0.99.22.4/zebra/zebra_routemap.c0000644000175000017500000004400512132522417014515 00000000000000/* 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 "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, "%% 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; } /* 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, "%% 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; } /* 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, "%% 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; } /* 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, "%% 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; } /* `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 *nexthop; char *ifname = rule; unsigned int ifindex; if (type == RMAP_ZEBRA) { if (strcasecmp(ifname, "any") == 0) return RMAP_MATCH; ifindex = ifname2ifindex(ifname); if (ifindex == 0) return RMAP_NOMATCH; nexthop = object; 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; if (inet_pton(AF_INET, argv[0], &src) <= 0) { vty_out (vty, "%% not a local address%s", VTY_NEWLINE); return CMD_WARNING; } pif = if_lookup_exact_address (src); 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 prefix_ipv4 p; if (type == RMAP_ZEBRA) { nexthop = object; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: if (nexthop->rtype != NEXTHOP_TYPE_IPV4) return RMAP_NOMATCH; p.family = AF_INET; p.prefix = nexthop->rgate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; 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 prefix_ipv4 p; if (type == RMAP_ZEBRA) { nexthop = object; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: if (nexthop->rtype != NEXTHOP_TYPE_IPV4) return RMAP_NOMATCH; p.family = AF_INET; p.prefix = nexthop->rgate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; 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 *nexthop; nexthop = object; 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-0.99.22.4/zebra/zebra_snmp.c0000644000175000017500000003571112177450262013651 00000000000000/* FIB SNMP. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "smux.h" #include "table.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 = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return NULL; /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) 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 = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return 0; /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) 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 = vrf_table (AFI_IP, SAFI_UNICAST, 0); 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-0.99.22.4/zebra/zebra_vty.c0000644000175000017500000017162612211105060013502 00000000000000/* 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 "zebra/zserv.h" /* General fucntion for static route. */ static int zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, const char *mask_str, const char *gate_str, const char *flag_str, const char *distance_str) { int ret; u_char distance; struct prefix p; struct in_addr gate; struct in_addr mask; const char *ifname; u_char flag = 0; ret = str2prefix (dest_str, &p); if (ret <= 0) { vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } /* Cisco like mask notation. */ if (mask_str) { ret = inet_aton (mask_str, &mask); if (ret == 0) { vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } p.prefixlen = ip_masklen (mask); } /* Apply mask for given prefix. */ apply_mask (&p); /* Administrative distance. */ if (distance_str) distance = atoi (distance_str); else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; /* Null0 static route. */ if ((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 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); else static_delete_ipv4 (&p, NULL, NULL, distance, 0); 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 (&p, NULL, NULL, flag, distance, 0); else static_delete_ipv4 (&p, NULL, NULL, distance, 0); return CMD_SUCCESS; } /* When gateway is A.B.C.D format, gate is treated as nexthop address other case gate is treated as interface name. */ ret = inet_aton (gate_str, &gate); if (ret) ifname = NULL; else ifname = gate_str; if (add_cmd) static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, distance, 0); else static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); return CMD_SUCCESS; } /* Static route configuration. */ DEFUN (ip_route, ip_route_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") { return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, NULL); } 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 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL); } 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 (vty, 1, argv[0], NULL, NULL, argv[1], NULL); } /* Mask as A.B.C.D format. */ DEFUN (ip_route_mask, ip_route_mask_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, NULL); } 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 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL); } 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 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL); } /* Distance option value. */ DEFUN (ip_route_distance, ip_route_distance_cmd, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], NULL, argv[2]); } 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 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3]); } 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 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2]); } DEFUN (ip_route_mask_distance, ip_route_mask_distance_cmd, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3]); } 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" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]); } 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" "Distance value for this route\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); } DEFUN (no_ip_route, no_ip_route_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") { return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, NULL); } 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") 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 (vty, 0, argv[0], NULL, NULL, NULL, NULL); } DEFUN (no_ip_route_mask, no_ip_route_mask_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") { return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, 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") 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 (vty, 0, argv[0], argv[1], NULL, NULL, NULL); } DEFUN (no_ip_route_distance, no_ip_route_distance_cmd, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") { return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], NULL, argv[2]); } 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 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3]); } 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 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2]); } DEFUN (no_ip_route_mask_distance, no_ip_route_mask_distance_cmd, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", NO_STR IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") { return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]); } 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 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]); } 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 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]); } 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) { struct rib *rib; struct nexthop *nexthop; RNODE_FOREACH_RIB (rn, rib) { vty_out (vty, "Routing entry for %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); 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_OSPF || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; struct tm *tm; uptime = time (NULL); uptime -= rib->uptime; tm = gmtime (&uptime); vty_out (vty, " Last update "); if (uptime < ONE_DAY_SECOND) vty_out (vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime < ONE_WEEK_SECOND) vty_out (vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else vty_out (vty, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); vty_out (vty, " ago%s", VTY_NEWLINE); } for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { char addrstr[32]; vty_out (vty, " %c", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " %s", inet_ntoa (nexthop->gate.ipv4)); if (nexthop->ifindex) vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " directly connected, %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " directly connected, %s", nexthop->ifname); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out (vty, " directly connected, Null0"); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { vty_out (vty, " (recursive"); switch (nexthop->rtype) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " via %s", inet_ntoa (nexthop->rgate.ipv4)); if (nexthop->rifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex)); vty_out (vty, ")"); break; case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s)", ifindex2ifname (nexthop->rifindex)); break; default: break; } } 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, addrstr, sizeof addrstr)) vty_out (vty, ", src %s", addrstr); } 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, addrstr, sizeof addrstr)) vty_out (vty, ", src %s", addrstr); } 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; int len = 0; char buf[BUFSIZ]; /* Nexthop information. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if (nexthop == rib->nexthop) { /* Prefix information. */ len = vty_out (vty, "%c%c%c %s/%d", zebra_route_char (rib->type), CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', inet_ntop (AF_INET, &rn->p.u.prefix, buf, BUFSIZ), rn->p.prefixlen); /* Distance and metric display. */ if (rib->type != ZEBRA_ROUTE_CONNECT && rib->type != ZEBRA_ROUTE_KERNEL) len += vty_out (vty, " [%d/%d]", rib->distance, rib->metric); } else vty_out (vty, " %c%*c", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', len - 3, ' '); switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4)); if (nexthop->ifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " is directly connected, %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s", nexthop->ifname); break; case NEXTHOP_TYPE_BLACKHOLE: vty_out (vty, " is directly connected, Null0"); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { vty_out (vty, " (recursive"); switch (nexthop->rtype) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " via %s", inet_ntoa (nexthop->rgate.ipv4)); if (nexthop->rifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex)); vty_out (vty, ")"); break; case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s)", ifindex2ifname (nexthop->rifindex)); break; default: break; } } 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_OSPF || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS || 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") { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; /* Show all IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) 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, show_ip_route_prefix_longer_cmd, "show ip route A.B.C.D/M longer-prefixes", SHOW_STR IP_STR "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Show route matching the specified Network/Mask pair only\n") { struct route_table *table; struct route_node *rn; struct rib *rib; struct prefix p; int ret; int first = 1; ret = str2prefix (argv[0], &p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) 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, show_ip_route_supernets_cmd, "show ip route supernets-only", SHOW_STR IP_STR "IP routing table\n" "Show supernet entries only\n") { struct route_table *table; struct route_node *rn; struct rib *rib; u_int32_t addr; int first = 1; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) 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, 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; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; /* Show matched type IPv4 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) 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, show_ip_route_addr_cmd, "show ip route A.B.C.D", SHOW_STR IP_STR "IP routing table\n" "Network in the IP routing table to display\n") { int ret; struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; rn = route_node_match (table, (struct prefix *) &p); if (! rn) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); return CMD_WARNING; } vty_show_ip_route_detail (vty, rn); route_unlock_node (rn); return CMD_SUCCESS; } DEFUN (show_ip_route_prefix, show_ip_route_prefix_cmd, "show ip route A.B.C.D/M", SHOW_STR IP_STR "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n") { int ret; struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "%% Malformed IPv4 address%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; rn = route_node_match (table, (struct prefix *) &p); if (! rn || rn->p.prefixlen != p.prefixlen) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); return CMD_WARNING; } vty_show_ip_route_detail (vty, rn); route_unlock_node (rn); return CMD_SUCCESS; } 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)) { 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 %-20s %s", "Route Source", "Routes", "FIB", 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); } /* 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; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; vty_show_ip_route_summary (vty, table); return CMD_SUCCESS; } /* Write IPv4 static route configuration. */ static int static_config_ipv4 (struct vty *vty) { struct route_node *rn; struct static_ipv4 *si; struct route_table *stable; int write; write = 0; /* Lookup table. */ stable = vrf_static_table (AFI_IP, SAFI_UNICAST, 0); if (! stable) return -1; for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { vty_out (vty, "ip route %s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); switch (si->type) { case STATIC_IPV4_GATEWAY: vty_out (vty, " %s", inet_ntoa (si->gate.ipv4)); break; case STATIC_IPV4_IFNAME: vty_out (vty, " %s", si->gate.ifname); break; case STATIC_IPV4_BLACKHOLE: vty_out (vty, " Null0"); break; } /* 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->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); 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" "Distance value for this prefix\n") { return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2]); } 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], argv[3]); } 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, argv[3]); } 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], argv[4]); } 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); } 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") 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); } 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") 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, argv[2]); } 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], argv[3]); } 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, argv[3]); } 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], argv[4]); } /* New RIB. Detailed information for IPv6 route. */ static void vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) { struct rib *rib; struct nexthop *nexthop; char buf[BUFSIZ]; RNODE_FOREACH_RIB (rn, rib) { vty_out (vty, "Routing entry for %s/%d%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), rn->p.prefixlen, VTY_NEWLINE); vty_out (vty, " Known via \"%s\"", zebra_route_string (rib->type)); vty_out (vty, ", distance %u, metric %u", rib->distance, rib->metric); if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) vty_out (vty, ", best"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); 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_RIPNG || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS || rib->type == ZEBRA_ROUTE_BGP) { time_t uptime; struct tm *tm; uptime = time (NULL); uptime -= rib->uptime; tm = gmtime (&uptime); vty_out (vty, " Last update "); if (uptime < ONE_DAY_SECOND) vty_out (vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime < ONE_WEEK_SECOND) vty_out (vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else vty_out (vty, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); vty_out (vty, " ago%s", VTY_NEWLINE); } for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { vty_out (vty, " %c", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' '); switch (nexthop->type) { case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: vty_out (vty, " %s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) vty_out (vty, ", %s", nexthop->ifname); else if (nexthop->ifindex) vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " directly connected, %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " directly connected, %s", nexthop->ifname); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { vty_out (vty, " (recursive"); switch (nexthop->rtype) { case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: vty_out (vty, " via %s)", inet_ntop (AF_INET6, &nexthop->rgate.ipv6, buf, BUFSIZ)); if (nexthop->rifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex)); break; case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s)", ifindex2ifname (nexthop->rifindex)); break; default: break; } } vty_out (vty, "%s", VTY_NEWLINE); } vty_out (vty, "%s", VTY_NEWLINE); } } static void vty_show_ipv6_route (struct vty *vty, struct route_node *rn, struct rib *rib) { struct nexthop *nexthop; int len = 0; char buf[BUFSIZ]; /* Nexthop information. */ for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { if (nexthop == rib->nexthop) { /* Prefix information. */ len = vty_out (vty, "%c%c%c %s/%d", zebra_route_char (rib->type), CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ', CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), rn->p.prefixlen); /* Distance and metric display. */ if (rib->type != ZEBRA_ROUTE_CONNECT && rib->type != ZEBRA_ROUTE_KERNEL) len += vty_out (vty, " [%d/%d]", rib->distance, rib->metric); } else vty_out (vty, " %c%*c", CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? '*' : ' ', len - 3, ' '); switch (nexthop->type) { case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: vty_out (vty, " via %s", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) vty_out (vty, ", %s", nexthop->ifname); else if (nexthop->ifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " is directly connected, %s", ifindex2ifname (nexthop->ifindex)); break; case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s", nexthop->ifname); break; default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) vty_out (vty, " inactive"); if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { vty_out (vty, " (recursive"); switch (nexthop->rtype) { case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFNAME: vty_out (vty, " via %s)", inet_ntop (AF_INET6, &nexthop->rgate.ipv6, buf, BUFSIZ)); if (nexthop->rifindex) vty_out (vty, ", %s", ifindex2ifname (nexthop->rifindex)); break; case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s)", ifindex2ifname (nexthop->rifindex)); break; default: break; } } if (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_RIPNG || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_BABEL || rib->type == ZEBRA_ROUTE_ISIS || 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_ipv6_route, show_ipv6_route_cmd, "show ipv6 route", SHOW_STR IP_STR "IPv6 routing table\n") { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; /* Show all IPv6 route. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); } return CMD_SUCCESS; } DEFUN (show_ipv6_route_prefix_longer, show_ipv6_route_prefix_longer_cmd, "show ipv6 route X:X::X:X/M longer-prefixes", SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 prefix\n" "Show route matching the specified Network/Mask pair only\n") { struct route_table *table; struct route_node *rn; struct rib *rib; struct prefix p; int ret; int first = 1; table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; ret = str2prefix (argv[0], &p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (prefix_match (&p, &rn->p)) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); } return CMD_SUCCESS; } DEFUN (show_ipv6_route_protocol, show_ipv6_route_protocol_cmd, "show ipv6 route " 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; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; /* Show matched type IPv6 routes. */ for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) if (rib->type == type) { if (first) { vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); } return CMD_SUCCESS; } DEFUN (show_ipv6_route_addr, show_ipv6_route_addr_cmd, "show ipv6 route X:X::X:X", SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 Address\n") { int ret; struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; rn = route_node_match (table, (struct prefix *) &p); if (! rn) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); return CMD_WARNING; } vty_show_ipv6_route_detail (vty, rn); route_unlock_node (rn); return CMD_SUCCESS; } DEFUN (show_ipv6_route_prefix, show_ipv6_route_prefix_cmd, "show ipv6 route X:X::X:X/M", SHOW_STR IP_STR "IPv6 routing table\n" "IPv6 prefix\n") { int ret; struct prefix_ipv6 p; struct route_table *table; struct route_node *rn; ret = str2prefix_ipv6 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; rn = route_node_match (table, (struct prefix *) &p); if (! rn || rn->p.prefixlen != p.prefixlen) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); return CMD_WARNING; } vty_show_ipv6_route_detail (vty, rn); route_unlock_node (rn); return CMD_SUCCESS; } /* 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; table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (! table) return CMD_SUCCESS; vty_show_ip_route_summary (vty, table); return CMD_SUCCESS; } /* * 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; table = vrf_table (AFI_IP6, SAFI_MULTICAST, 0); 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_ipv6_route (vty, rn, rib); } return CMD_SUCCESS; } /* Write IPv6 static route configuration. */ static int static_config_ipv6 (struct vty *vty) { struct route_node *rn; struct static_ipv6 *si; int write; char buf[BUFSIZ]; struct route_table *stable; write = 0; /* Lookup table. */ stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, 0); if (! stable) return -1; for (rn = route_top (stable); rn; rn = route_next (rn)) for (si = rn->info; si; si = si->next) { vty_out (vty, "ipv6 route %s/%d", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), rn->p.prefixlen); switch (si->type) { case STATIC_IPV6_GATEWAY: vty_out (vty, " %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ)); break; case STATIC_IPV6_IFNAME: vty_out (vty, " %s", si->ifname); break; case STATIC_IPV6_GATEWAY_IFNAME: vty_out (vty, " %s %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname); break; } 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->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); vty_out (vty, "%s", VTY_NEWLINE); write = 1; } return write; } #endif /* HAVE_IPV6 */ /* Static ip route configuration write function. */ static int zebra_ip_config (struct vty *vty) { int write = 0; write += static_config_ipv4 (vty); #ifdef HAVE_IPV6 write += static_config_ipv6 (vty); #endif /* HAVE_IPV6 */ return write; } /* ip protocol configuration write function */ static int config_write_protocol(struct vty *vty) { int i; 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 "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; 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; } return 0; } static int zebra_server_send_message(struct zserv *client) { if (client->t_suicide) return -1; 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; } return 0; } static void zserv_create_header (struct stream *s, uint16_t cmd) { /* 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, 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); #ifdef HAVE_STRUCT_SOCKADDR_DL stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); #else stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); #endif /* HAVE_STRUCT_SOCKADDR_DL */ /* 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 (! client->ifinfo) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_ADD); zserv_encode_interface (s, ifp); 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 (! client->ifinfo) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_DELETE); zserv_encode_interface (s, ifp); 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 [|