diff options
76 files changed, 45393 insertions, 0 deletions
diff --git a/isisd/AUTHORS b/isisd/AUTHORS new file mode 100644 index 00000000..d9f98b22 --- /dev/null +++ b/isisd/AUTHORS @@ -0,0 +1,3 @@ +Sampo Saaristo <sambo@cs.tut.fi> +Ofer Wald <ofersf@islands.co.il> +Hannes Gredler <hannes@gredler.at> diff --git a/isisd/COPYING b/isisd/COPYING new file mode 100644 index 00000000..08d6e50e --- /dev/null +++ b/isisd/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 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. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/isisd/ChangeLog b/isisd/ChangeLog new file mode 100644 index 00000000..78580ea1 --- /dev/null +++ b/isisd/ChangeLog @@ -0,0 +1,69 @@ +Version 0.0.7 to 0.0.8 +====================== + +o A bug in handling of other ISs fragments fixed +o hello interval now specified in *seconds* +o replaced the adj->ipv[46]_addr tables with linked lists + +Version 0.0.6 to 0.0.7 (Oct 29 2002) +====================== + +o changed to zebra-0.93b +o fixed a seg in SPF +o handling/generation of LSP fragments +o domain/area/circuit password + +Version 0.0.5 to 0.0.6 (Jul 4 2002) +====================== + +o lots of changes to SPF + - runs the SPF for IPv4 and IPv6 separately + - a number of bugs fixed + - simplified the implementation + - "7.2.7 Removal of excess paths" implemented +o ported to freebsd (tested in 4.5-STABLE and 4.6-STABLE) +o moved to zebra-0.93-pre2 +o "show isis topology" command added +o "show (ip|ipv6) route isis commands added to zebra +o a number of fixes and additions (e.g. checksum calculation and DIS state +change event) by BeomSeok Gwak added + +Version 0.0.4 to 0.0.5 (Apr 26 2002) +====================== + +o changed to zebra-0.93-pre1 +o number of memory leaks + small bugs fixed +o a bug related to processing of neigbors when installing routes fixed + +Version 0.0.3 to 0.0.4 (Feb 27 2002) +====================== + +o initial version of SPT algorithm +o installing routes though zebrad +o isis debug commands +o work on IS-IS events (e.g. circuit state change) + +Version 0.0.2 to 0.0.3 (Jan 17 2002) +====================== + +o LSP handling improved +o generation of pseudonode LSPs +o DR election enhanced +o support for p2p interfaces +o support for topology simulation +o more detailed output for show commands + +Version 0.0.1 to 0.0.2 (Dec 13 2001) +====================== + +o circuit state machine (isis_csm.[ch]) added +o lot of work on LSP generation +o ISO checksum +o uses DGRAM sockets instead of RAW +o gets IP(v6) addresses from zebra +o debug can be controlled with "debug isis" command +o read support for TE tlvs +o work started on p2p interfaces +o work started on isis events + + diff --git a/isisd/INSTALL-0.0.4 b/isisd/INSTALL-0.0.4 new file mode 100644 index 00000000..c9843915 --- /dev/null +++ b/isisd/INSTALL-0.0.4 @@ -0,0 +1,18 @@ +ISISd package for zebra 0.92a installation instructions: + +1. grab the zebra 0.92a package from www.zebra.org +2. unpack the package using tar -zxvf zebra-0.92a.tar.gz +3. enter the zebra-092a directory +4. copy the contents of the isisd package into the zebra dir +5. enter the isisd/modified directory +6. use the README file and copy the files to the appropriate zebra dirs + (the simplest way to do so would be 'source README') +7. enter the main zebra directory and issue 'automake','autoconf' and + 'autoheader'. if using automake version 1.5 and up use the '-i' option. +8. run './configure --enable-isisd' (you may use other zebra config commands) +9. run 'make' +10. find your self something entertaining to do for the next couple of minutes +11. you can issue 'make install' or simply work from the isisd directory + +for any problems, contact the developers at the sourceforge site +http://www.sf.net/projects/isisd diff --git a/isisd/Makefile.am b/isisd/Makefile.am new file mode 100644 index 00000000..b9a0c7cb --- /dev/null +++ b/isisd/Makefile.am @@ -0,0 +1,55 @@ +## Process this file with automake to produce Makefile.in. + +# INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -Itopology +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 +LIBS = @LIBS@ +noinst_LIBRARIES = libisis.a +sbin_PROGRAMS = isisd + +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_network.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 + +isisd_SOURCES = \ + isis_main.c $(libisis_a_SOURCES) + +isisd_LDADD = ../lib/libzebra.a + +sysconf_DATA = isisd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done + +depend: + @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c + +## File dependency. +isis_adjacency.o : isis_adjacency.c ../lib/version.h ../lib/log.h \ + ../isisd/isis_adjacency.h +isis_pdu.o : isis_pdu.c ../lib/log.h ../isisd/isisd.h \ + ../isisd/isis_constants.h ../isisd/isis_adjacency.h \ + ../isisd/isis_pdu.h +isis_circuit.o : isis_circuit.c ../isisd/isis_circuit.h diff --git a/isisd/Makefile.in b/isisd/Makefile.in new file mode 100644 index 00000000..46aae735 --- /dev/null +++ b/isisd/Makefile.in @@ -0,0 +1,463 @@ +# Makefile.in generated by automake 1.6.2 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ + +# INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -Itopology +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +ISISD = @ISISD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA = @INSTALL@ -m 600 +LIBS = @LIBS@ +noinst_LIBRARIES = libisis.a +sbin_PROGRAMS = isisd + +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_network.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 + + +isisd_SOURCES = \ + isis_main.c $(libisis_a_SOURCES) + + +isisd_LDADD = ../lib/libzebra.a + +sysconf_DATA = isisd.conf.sample + +EXTRA_DIST = $(sysconf_DATA) +subdir = isisd +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libisis_a_AR = $(AR) cru +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_network.$(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) +sbin_PROGRAMS = isisd$(EXEEXT) +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_network.$(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) +isisd_OBJECTS = $(am_isisd_OBJECTS) +isisd_DEPENDENCIES = ../lib/libzebra.a +isisd_LDFLAGS = +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/dict.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_adjacency.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_circuit.Po ./$(DEPDIR)/isis_csm.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_dr.Po ./$(DEPDIR)/isis_dynhn.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_events.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_flags.Po ./$(DEPDIR)/isis_lsp.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_main.Po ./$(DEPDIR)/isis_misc.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_network.Po ./$(DEPDIR)/isis_pdu.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_route.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_routemap.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_spf.Po ./$(DEPDIR)/isis_tlv.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/isis_zebra.Po ./$(DEPDIR)/isisd.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/iso_checksum.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CFLAGS = @CFLAGS@ +DIST_SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) +DATA = $(sysconf_DATA) + +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README $(noinst_HEADERS) AUTHORS COPYING ChangeLog \ + Makefile.am Makefile.in TODO +SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu isisd/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libisis.a: $(libisis_a_OBJECTS) $(libisis_a_DEPENDENCIES) + -rm -f libisis.a + $(libisis_a_AR) libisis.a $(libisis_a_OBJECTS) $(libisis_a_LIBADD) + $(RANLIB) libisis.a +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + p1=`echo "$$p1" | sed -e 's,^.*/,,'`; \ + f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + f=`echo "$$f" | sed -e 's,^.*/,,'`; \ + echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \ + rm -f $(DESTDIR)$(sbindir)/$$f; \ + done + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) +isisd$(EXEEXT): $(isisd_OBJECTS) $(isisd_DEPENDENCIES) + @rm -f isisd$(EXEEXT) + $(LINK) $(isisd_LDFLAGS) $(isisd_OBJECTS) $(isisd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +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_circuit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_csm.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_network.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_pdu.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@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c `cygpath -w $<` +CCDEPMODE = @CCDEPMODE@ +uninstall-info-am: +sysconfDATA_INSTALL = $(INSTALL_DATA) + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(sysconf_DATA)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \ + rm -f $(DESTDIR)$(sysconfdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-sbinPROGRAMS install-sysconfDATA + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \ + uninstall-sysconfDATA + +.PHONY: GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-sbinPROGRAMS distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-sbinPROGRAMS install-strip install-sysconfDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-info-am uninstall-sbinPROGRAMS uninstall-sysconfDATA + + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done + +depend: + @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c + +isis_adjacency.o : isis_adjacency.c ../lib/version.h ../lib/log.h \ + ../isisd/isis_adjacency.h +isis_pdu.o : isis_pdu.c ../lib/log.h ../isisd/isisd.h \ + ../isisd/isis_constants.h ../isisd/isis_adjacency.h \ + ../isisd/isis_pdu.h +isis_circuit.o : isis_circuit.c ../isisd/isis_circuit.h +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/isisd/README b/isisd/README new file mode 100644 index 00000000..6e2198dc --- /dev/null +++ b/isisd/README @@ -0,0 +1,20 @@ +Modified files in the ZEBRA-0.92a package. + + ../configure.in + ../Makefile.am + ../acconfig.h + ../lib/log.h + ../lib/memory.h + ../lib/vty.c + - case ISIS_NODE: + ../lib/command.c + - case ISIS_NODE: + ../lib/command.h + - ISIS_NODE, /* IS-IS protocol mode */ + - str #definitions + + +Constraints + + o Maximum number of interfaces 255 + diff --git a/isisd/TODO b/isisd/TODO new file mode 100644 index 00000000..e3c1352e --- /dev/null +++ b/isisd/TODO @@ -0,0 +1,10 @@ +Things in the TODO list for the near future + +o select nearest L2 when running SPF for L1 +o remove the routes when holding time for nexthop expires +o redist +o autosummary + +Not so urgent: + +o Mesh groups diff --git a/isisd/dict.c b/isisd/dict.c new file mode 100644 index 00000000..4c787ac5 --- /dev/null +++ b/isisd/dict.c @@ -0,0 +1,1496 @@ +/* + * Dictionary Abstract Data Type + * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net> + * + * 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.c,v 1.1 2003/12/23 08:09:47 jardin Exp $ + * $Name: $ + */ + +#include <stdlib.h> +#include <stddef.h> +#include <assert.h> +#define DICT_IMPLEMENTATION +#include "dict.h" + +#ifdef KAZLIB_RCSID +static const char rcsid[] = "$Id: dict.c,v 1.1 2003/12/23 08:09:47 jardin Exp $"; +#endif + +/* + * 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 = malloc(sizeof *new); + + 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)); + free(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) +{ +#ifdef KAZLIB_OBSOLESCENT_DEBUG + assert ("call to obsolescent function dict_free()" && 0); +#endif + 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 malloc(sizeof *dnode_alloc(NULL)); +} + +static void dnode_free(dnode_t *node, void *context) +{ + free(node); +} + +dnode_t *dnode_create(void *data) +{ + dnode_t *new = malloc(sizeof *new); + 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)); + free(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 <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> + +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 = malloc(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 <key> <val> 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 <key> <val> add value to dictionary\n" + "d <key> delete value from dictionary\n" + "l <key> lookup value in dictionary\n" + "( <key> lookup lower bound\n" + ") <key> lookup upper bound\n" + "# <num> switch to alternate dictionary (0-9)\n" + "j <num> <num> 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 < sizeof darray / sizeof *darray; 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 diff --git a/isisd/dict.h b/isisd/dict.h new file mode 100644 index 00000000..2977a90f --- /dev/null +++ b/isisd/dict.h @@ -0,0 +1,144 @@ +/* + * Dictionary Abstract Data Type + * Copyright (C) 1997 Kaz Kylheku <kaz@ashi.footprints.net> + * + * 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.1 2003/12/23 08:09:48 jardin Exp $ + * $Name: $ + */ + +#ifndef DICT_H +#define DICT_H + +#include <limits.h> +#ifdef KAZLIB_SIDEEFFECT_DEBUG +#include "sfx.h" +#endif + +/* + * 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 { + #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + 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; + #else + int dict_dummy; + #endif +} 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 { + #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + 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; + #else + int dict_dummmy; + #endif +} dict_t; + +typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); + +typedef struct dict_load_t { + #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + dict_t *dict_dictptr; + dnode_t dict_nilnode; + #else + int dict_dummmy; + #endif +} 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 *); + +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +#ifdef KAZLIB_SIDEEFFECT_DEBUG +#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) +#else +#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) +#endif +#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)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/isisd/include-netbsd/clnp.h b/isisd/include-netbsd/clnp.h new file mode 100644 index 00000000..6bc3d257 --- /dev/null +++ b/isisd/include-netbsd/clnp.h @@ -0,0 +1,547 @@ +/* $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 */
diff --git a/isisd/include-netbsd/esis.h b/isisd/include-netbsd/esis.h new file mode 100644 index 00000000..ded864e6 --- /dev/null +++ b/isisd/include-netbsd/esis.h @@ -0,0 +1,146 @@ +/* $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 <machine/endian.h>
+
+#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 */
diff --git a/isisd/include-netbsd/iso.h b/isisd/include-netbsd/iso.h new file mode 100644 index 00000000..714b42d6 --- /dev/null +++ b/isisd/include-netbsd/iso.h @@ -0,0 +1,208 @@ +/* $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 <sys/ansi.h> +#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 <netinet/in.h> +#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 */ + +#include <sys/cdefs.h> + +__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_ */ diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c new file mode 100644 index 00000000..8079bd17 --- /dev/null +++ b/isisd/isis_adjacency.c @@ -0,0 +1,508 @@ +/* + * 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 <stdio.h> +#include <limits.h> +#include <string.h> +#include <zebra.h> +#include <net/ethernet.h> + + +#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/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" + + +extern struct isis *isis; + + +struct isis_adjacency * +adj_alloc (u_char *id) +{ + struct isis_adjacency *adj; + + adj = XMALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency)); + memset (adj, 0, 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; + } + + memcpy (adj->snpa, snpa, 6); + 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 (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + 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 (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0) + return adj; + } + + return NULL; +} + +/* + * When we recieve a NULL list, we will know its p2p + */ +void +isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb) +{ + struct isis_adjacency *adj2; + struct listnode *node; + + if (adjdb) { + for (node = listhead (adjdb); node; nextnode (node)) { + adj2 = getdata (node); + if (adj2 == adj) + break; + } + listnode_delete (adjdb, node); + } + + if (adj->ipv4_addrs) + list_delete (adj->ipv4_addrs); +#ifdef HAVE_IPV6 + if (adj->ipv6_addrs) + list_delete (adj->ipv6_addrs); +#endif + if (adj) { + XFREE (MTYPE_ISIS_ADJACENCY,adj); + } else { + zlog_info ("tried to delete a non-existent adjacency"); + } + + + + return; +} + +void +isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, + char *reason) + +{ + int old_state; + int level = adj->level; + struct isis_circuit *circuit; + + old_state = adj->adj_state; + adj->adj_state = state; + + circuit = adj->circuit; + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_info ("ISIS-Adj (%s): Adjacency state change %d->%d: %s", + circuit->area->area_tag, + old_state, + state, + reason ? reason : "unspecified"); + } + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + if (state == ISIS_ADJ_UP) + circuit->upadjcount[level-1]++; + if (state == ISIS_ADJ_DOWN) { + isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]); + circuit->upadjcount[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]); + } else if (state == ISIS_ADJ_UP) { /* p2p interface */ + if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) + send_hello (circuit, 1); + + /* 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,1); + send_csnp (circuit,2); + } else if (state == ISIS_ADJ_DOWN) { /* p2p interface */ + adj->circuit->u.p2p.neighbor = NULL; + isis_delete_adj (adj, NULL); + } + 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_info ("%s", dyn->name.name); + + zlog_info ("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_info ("IPv4 Addresses:"); + + for (node = listhead (adj->ipv4_addrs); node; nextnode (node)) { + ipv4_addr = getdata (node); + zlog_info ("%s", inet_ntoa(*ipv4_addr)); + } + } + +#ifdef HAVE_IPV6 + if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { + zlog_info ("IPv6 Addresses:"); + for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) { + ipv6_addr = getdata (node); + inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN); + zlog_info ("%s", ip6); + } + } +#endif /* HAVE_IPV6 */ + zlog_info ("Speaks: %s", nlpid2string(&adj->nlpids)); + + + return; +} + +int +isis_adj_expire (struct thread *thread) +{ + struct isis_adjacency *adj; + int level; + + /* + * Get the adjacency + */ + adj = THREAD_ARG (thread); + assert (adj); + level = adj->level; + + /* trigger the adj expire event */ + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired"); + + return 0; +} + +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 */ +} + +/* + * show clns/isis neighbor (detail) + */ +void +isis_adj_print_vty2 (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); + vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now); + vty_out (vty, "%-10s", snpa_print (adj->snpa)); + vty_out (vty, "%s", VTY_NEWLINE); + } + + if (detail == ISIS_UI_LEVEL_DETAIL) { + level = adj->level; + if (adj->circuit) + vty_out (vty, "%s Interface: %s", + VTY_NEWLINE, + adj->circuit->interface->name); /* interface name */ + else + vty_out (vty, "NULL circuit!%s", VTY_NEWLINE); + vty_out (vty, ", Level: %u", adj->level); /* level */ + vty_out (vty, ", State: %s", adj_state2string (adj->adj_state)); + now = time (NULL); + vty_out (vty, ", Expires in %s", + time2string (adj->last_upd + adj->hold_time - now)); + vty_out (vty, "%s Adjacency flaps: %u", + VTY_NEWLINE, + adj->flaps); + vty_out (vty, ", Last: %s ago", time2string(now - adj->last_flap)); + vty_out (vty, "%s Circuit type: %s", + VTY_NEWLINE, + circuit_t2string(adj->circuit_t)); + vty_out (vty, ", Speaks: %s", nlpid2string(&adj->nlpids)); + vty_out (vty, "%s SNPA: %s", + VTY_NEWLINE, + snpa_print (adj->snpa)); + 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 Priority: %u", + VTY_NEWLINE, + adj->prio[adj->level-1]); + + vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s", + 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_NEWLINE); + + if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { + vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE); + for (node = listhead (adj->ipv4_addrs);node; nextnode (node)) { + ip_addr = getdata (node); + 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 Addresses:%s", VTY_NEWLINE); + for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) { + ipv6_addr = getdata (node); + inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN); + vty_out (vty, " %s%s", ip6, VTY_NEWLINE); + } + } +#endif /* HAVE_IPV6 */ + vty_out (vty, "%s", VTY_NEWLINE); + } + return; +} + +void +isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty) { + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF); +} + +void +isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) { + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL); +} + +void +isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) { + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE); +} + +void +isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty) +{ + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF); +} + +void +isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) +{ + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL); +} + +void +isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) +{ + isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE); +} + +void +isis_adjdb_iterate (struct list *adjdb, void (*func)(struct isis_adjacency*, + void *), void *arg) +{ + struct listnode *node; + struct isis_adjacency *adj; + for (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + (*func)(adj, arg); + } +} + +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 (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + 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 (node = listhead (adjdb); node; nextnode (node)) { + adj = getdata (node); + + if (!adj) { + zlog_warn ("isis_adj_build_up_list(): NULL adj"); + return; + } + + if (adj->adj_state == ISIS_ADJ_UP) + listnode_add (list, adj); + } + + return; +} + diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h new file mode 100644 index 00000000..5c0772cc --- /dev/null +++ b/isisd/isis_adjacency.h @@ -0,0 +1,126 @@ +/* + * 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_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; +#ifdef HAVE_IPV6 + struct list *ipv6_addrs; +#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 (struct isis_adjacency *adj, struct list *adjdb); +void isis_adj_state_change (struct isis_adjacency *adj, + enum isis_adj_state state, 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); +void isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty); +void isis_adj_print_vty_extensive (struct isis_adjacency *adj, + struct vty *vty); +void isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty); +void isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, + struct vty *vty); +void isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, + struct vty *vty); + +void isis_adj_build_neigh_list (struct list *adjdb, struct list *list); +void isis_adj_build_up_list (struct list *adjdb, struct list *list); +void isis_adjdb_iterate (struct list *adjdb, + void (*func)(struct isis_adjacency*, + void *), void *arg); + +#endif /* ISIS_ADJACENCY_H */ + diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c new file mode 100644 index 00000000..f37c314e --- /dev/null +++ b/isisd/isis_circuit.c @@ -0,0 +1,2200 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <zebra.h> +#include <net/ethernet.h> + +#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_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/isis_flags.h" +#include "isisd/isisd.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_events.h" + +extern struct thread_master *master; +extern struct isis *isis; + +struct isis_circuit * +isis_circuit_new () +{ + struct isis_circuit *circuit; + int i; + + circuit = XMALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit)); + if (circuit) { + memset (circuit, 0, sizeof (struct isis_circuit)); + /* set default metrics for circuit */ + for (i = 0; i < 2; i++) { + circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRICS; + circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; + circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; + circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; + } + } else { + zlog_err ("Can't malloc isis circuit"); + return NULL; + } + + return circuit; +} + + +void +isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area) +{ + int i; + circuit->area = area; + /* + * The level for the circuit is same as for the area, unless configured + * otherwise. + */ + circuit->circuit_is_type = area->is_type; + /* + * Default values + */ + for (i = 0; i < 2; i++) { + circuit->hello_interval[i] = HELLO_INTERVAL; + circuit->hello_multiplier[i] = HELLO_MULTIPLIER; + circuit->csnp_interval[i] = CSNP_INTERVAL; + circuit->psnp_interval[i] = PSNP_INTERVAL; + circuit->u.bc.priority[i] = DEFAULT_PRIORITY; + } + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + circuit->u.bc.adjdb[0] = list_new (); + circuit->u.bc.adjdb[1] = list_new (); + circuit->u.bc.pad_hellos = 1; + } + circuit->lsp_interval = LSP_INTERVAL; + + /* + * Add the circuit into area + */ + listnode_add (area->circuit_list, circuit); + + circuit->idx = flags_get_index (&area->flags); + circuit->lsp_queue = list_new (); + + return; +} + +void +isis_circuit_deconfigure (struct isis_circuit *circuit, + struct isis_area *area) +{ + + /* Remove circuit from area */ + listnode_delete (area->circuit_list, circuit); + /* Free the index of SRM and SSN flags */ + flags_free_index (&area->flags, circuit->idx); + + 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 (node = listhead (list); node; nextnode (node)) { + circuit = getdata (node); + if (circuit->interface == ifp) + 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 (!isis->area_list) + return NULL; + + for (node = listhead (isis->area_list); node; nextnode (node)) { + area = getdata (node); + circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (circuit) + return circuit; + } + + return circuit_lookup_by_ifp (ifp, isis->init_circ_list); +} + +void +isis_circuit_del (struct isis_circuit *circuit) +{ + + if (!circuit) + return; + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + /* destroy adjacency databases */ + list_delete (circuit->u.bc.adjdb[0]); + list_delete (circuit->u.bc.adjdb[1]); + /* destroy neighbour lists */ + if (circuit->u.bc.lan_neighs[0]) + list_delete (circuit->u.bc.lan_neighs[0]); + if (circuit->u.bc.lan_neighs[1]) + list_delete (circuit->u.bc.lan_neighs[1]); + /* destroy addresses */ + } + if (circuit->ip_addrs) + list_delete (circuit->ip_addrs); +#ifdef HAVE_IPV6 + if (circuit->ipv6_link) + list_delete (circuit->ipv6_link); + if (circuit->ipv6_non_link) + list_delete (circuit->ipv6_non_link); +#endif /* HAVE_IPV6 */ + + /* and lastly the circuit itself */ + XFREE (MTYPE_ISIS_CIRCUIT, circuit); + + return; +} + +void +isis_circuit_add_addr (struct isis_circuit *circuit, + struct connected *conn) +{ + struct prefix_ipv4 *ipv4; + u_char buf [BUFSIZ]; +#ifdef HAVE_IPV6 + struct prefix_ipv6 *ipv6; +#endif /* HAVE_IPV6 */ + if (!circuit->ip_addrs) { + circuit->ip_addrs = list_new (); + } +#ifdef HAVE_IPV6 + if (!circuit->ipv6_link) { + circuit->ipv6_link = list_new (); + } + if (!circuit->ipv6_non_link) { + circuit->ipv6_non_link = list_new (); + } +#endif /* HAVE_IPV6 */ + + memset (&buf, 0, BUFSIZ); + if (conn->address->family == AF_INET) { + ipv4 = prefix_ipv4_new (); + ipv4->prefixlen = conn->address->prefixlen; + ipv4->prefix = conn->address->u.prefix4; + listnode_add (circuit->ip_addrs, ipv4); + prefix2str (conn->address, buf, BUFSIZ); +#ifdef EXTREME_DEBUG + zlog_info ("Added IP address %s to circuit %d", buf, + circuit->circuit_id); +#endif /* EXTREME_DEBUG */ + } +#ifdef HAVE_IPV6 + if (conn->address->family == AF_INET6) { + ipv6 = prefix_ipv6_new (); + ipv6->prefixlen = conn->address->prefixlen; + ipv6->prefix = conn->address->u.prefix6; + if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) { + listnode_add (circuit->ipv6_link, ipv6); + } else { + listnode_add (circuit->ipv6_non_link, ipv6); + } + prefix2str (conn->address, buf, BUFSIZ); +#ifdef EXTREME_DEBUG + zlog_info ("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) +{ + +} + +void +isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp) +{ + struct listnode *node; + struct connected *conn; + + circuit->interface = ifp; + ifp->info = circuit; + + circuit->circuit_id = ifp->ifindex % 255; /* FIXME: Why not ? */ + + /* isis_circuit_update_addrs (circuit, ifp); */ + + if (if_is_broadcast (ifp)) { + circuit->circ_type = CIRCUIT_T_BROADCAST; + /* + * Get the Hardware Address + */ +#ifdef HAVE_SOCKADDR_DL + 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); +#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_info ("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_SOCKADDR_DL */ + } else if (if_is_pointopoint (ifp)) { + circuit->circ_type = CIRCUIT_T_P2P; + } else { + zlog_warn ("isis_circuit_if_add: unsupported media"); + } + + for (node = ifp->connected ? listhead (ifp->connected) : NULL; node; + nextnode (node)) { + conn = getdata (node); + isis_circuit_add_addr (circuit, conn); + } + + return; +} + +void +isis_circuit_update_params (struct isis_circuit *circuit, + struct interface *ifp) +{ + assert (circuit); + + if (circuit->circuit_id != ifp->ifindex) { + zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id, + ifp->ifindex); + circuit->circuit_id = ifp->ifindex % 255; + } + + /* FIXME: Why is this needed? shouldn't we compare to the area's mtu */ + /* Ofer, this was here in case someone changes the mtu (e.g. with ifconfig) + The areas MTU is the minimum of mtu's of circuits in the area + now we can't catch the change + if (circuit->mtu != ifp->mtu) { + zlog_warn ("changing circuit mtu %d->%d", circuit->mtu, + ifp->mtu); + circuit->mtu = ifp->mtu; + } + */ + /* + * Get the Hardware Address + */ +#ifdef HAVE_SOCKADDR_DL + 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); +#else + if (circuit->interface->hw_addr_len != ETH_ALEN) { + zlog_warn ("unsupported link layer"); + } else { + if (memcmp(circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN)) { + zlog_warn ("changing circuit snpa %s->%s", + snpa_print (circuit->u.bc.snpa), + snpa_print (circuit->interface->hw_addr)); + } + } +#endif + + + + if (if_is_broadcast (ifp)) { + circuit->circ_type = CIRCUIT_T_BROADCAST; + } else if (if_is_pointopoint (ifp)) { + circuit->circ_type = CIRCUIT_T_P2P; + } else { + zlog_warn ("isis_circuit_update_params: unsupported media"); + } + + return; +} + +void +isis_circuit_if_del (struct isis_circuit *circuit) +{ + circuit->interface->info = NULL; + circuit->interface = NULL; + + return; +} + +void +isis_circuit_up (struct isis_circuit *circuit) +{ + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + 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->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->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->circuit_is_type & IS_LEVEL_1) + circuit->u.bc.t_run_dr[0] = + thread_add_timer (master, isis_run_dr_l1, circuit, + 2 * circuit->hello_multiplier[0] * circuit->hello_interval[0]); + if (circuit->circuit_is_type & IS_LEVEL_2) + circuit->u.bc.t_run_dr[1] = + thread_add_timer (master, isis_run_dr_l2, circuit, + 2 * circuit->hello_multiplier[1] * circuit->hello_interval[1]); + } else { + /* initializing the hello send threads + * for a ptp IF + */ + thread_add_event (master, send_p2p_hello, circuit, 0); + + } + + /* initializing PSNP timers */ + if (circuit->circuit_is_type & IS_LEVEL_1) { + circuit->t_send_psnp[0] = thread_add_timer (master, + send_l1_psnp, + circuit, + isis_jitter + (circuit->psnp_interval[0], + PSNP_JITTER)); + } + + if (circuit->circuit_is_type & IS_LEVEL_2) { + circuit->t_send_psnp[1] = thread_add_timer (master, + send_l2_psnp, + circuit, + isis_jitter + (circuit->psnp_interval[1], + PSNP_JITTER)); + + } + + /* initialize the circuit streams */ + 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)); + + /* unified init for circuits */ + isis_sock_init (circuit); + +#ifdef GNU_LINUX + circuit->t_read = thread_add_read (master, isis_receive, circuit, + circuit->fd); +#else + circuit->t_read = thread_add_timer (master, isis_receive, circuit, + circuit->fd); +#endif + return; +} + +void +isis_circuit_down (struct isis_circuit *circuit) +{ + /* Cancel all active threads -- FIXME: wrong place*/ + if (circuit->t_read) + thread_cancel (circuit->t_read); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + if (circuit->u.bc.t_send_lan_hello[0]) + thread_cancel (circuit->u.bc.t_send_lan_hello[0]); + if (circuit->u.bc.t_send_lan_hello[1]) + thread_cancel (circuit->u.bc.t_send_lan_hello[1]); + } else if (circuit->circ_type == CIRCUIT_T_P2P) { + if (circuit->u.p2p.t_send_p2p_hello) + thread_cancel (circuit->u.p2p.t_send_p2p_hello); + } + /* close the socket */ + close (circuit->fd); + + 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; +} + +int +isis_interface_config_write (struct vty *vty) +{ + + int write = 0; + listnode node; + listnode node2; + listnode node3; + struct interface *ifp; + struct isis_area *area; + struct isis_circuit *c; + struct prefix_ipv4 *ip; + int i; +#ifdef HAVE_IPV6 + struct prefix_ipv6 *ipv6; +#endif /*HAVE_IPV6 */ + + char buf[BUFSIZ]; + + + LIST_LOOP (iflist, ifp, node) + { + /* 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 */ + LIST_LOOP (isis->area_list, area, node2) + { + c = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (c) { + if (c->ip_router) { + vty_out (vty, " ip router isis %s%s",area->area_tag,VTY_NEWLINE); + write++; + } +#ifdef HAVE_IPV6 + if (c->ipv6_router) { + vty_out (vty, " ipv6 router isis %s%s",area->area_tag,VTY_NEWLINE); + write++; + } +#endif /* HAVE_IPV6 */ + /* ipv4 addresses - FIXME: those should be related to interface*/ + if (c->ip_addrs) {LIST_LOOP (c->ip_addrs,ip, node3) + { + vty_out (vty, " ip%s address %s/%d%s", + ip->family == AF_INET ? "" : "v6", + inet_ntop (ip->family, &ip->prefix, buf, BUFSIZ), ip->prefixlen, + VTY_NEWLINE); + write++; + }} + + /* ipv6 addresses - FIXME: those should be related to interface*/ +#ifdef HAVE_IPV6 + if (c->ipv6_link) {LIST_LOOP (c->ipv6_link, ipv6, node3) + { + vty_out (vty, " ip%s address %s/%d%s", + ipv6->family == AF_INET ? "" : "v6", + inet_ntop (ipv6->family, &ipv6->prefix, buf, BUFSIZ), + ipv6->prefixlen,VTY_NEWLINE); + write++; + }} + if (c->ipv6_non_link) {LIST_LOOP (c->ipv6_non_link, ipv6, node3) + { + vty_out (vty, " ip%s address %s/%d%s", + ipv6->family == AF_INET ? "" : "v6", + inet_ntop (ipv6->family, &ipv6->prefix, buf, BUFSIZ), + ipv6->prefixlen, VTY_NEWLINE); + write++; + }} +#endif /* HAVE_IPV6 */ + + /* ISIS - circuit type */ + if (c->circuit_is_type == IS_LEVEL_1) { + vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE); + write ++; + } else {if (c->circuit_is_type == IS_LEVEL_2) { + vty_out (vty, " isis circuit-type level-2-only%s", VTY_NEWLINE); + write ++; + }} + + /* ISIS - CSNP interval - FIXME: compare to cisco*/ + if (c->csnp_interval[0] == c->csnp_interval[1]) { + if (c->csnp_interval[0] != CSNP_INTERVAL) { + vty_out (vty, " isis csnp-interval %d%s", c->csnp_interval[0], + VTY_NEWLINE); + write ++; + } + } else { + for (i=0;i<2;i++) { + if (c->csnp_interval[1] != CSNP_INTERVAL) { + vty_out (vty, " isis csnp-interval %d level-%d%s", + c->csnp_interval[1],i+1, VTY_NEWLINE); + write ++; + } + } + } + + /* ISIS - Hello padding - Defaults to true so only display if false */ + if (c->circ_type == CIRCUIT_T_BROADCAST && !c->u.bc.pad_hellos) { + vty_out (vty, " no isis hello padding%s", VTY_NEWLINE); + write ++; + } + + /* ISIS - Hello interval - FIXME: compare to cisco */ + if (c->hello_interval[0] == c->hello_interval[1]) { + if (c->hello_interval[0] != HELLO_INTERVAL) { + vty_out (vty, " isis hello-interval %d%s", c->hello_interval[0], + VTY_NEWLINE); + write ++; + } + } else { + for (i=0;i<2;i++) { + if (c->hello_interval[i] != HELLO_INTERVAL) { + if (c->hello_interval[i] == HELLO_MINIMAL) { + vty_out (vty, " isis hello-interval minimal level-%d%s", i+1, + VTY_NEWLINE); + } else { + vty_out (vty, " isis hello-interval %d level-%d%s", + c->hello_interval[i],i+1, VTY_NEWLINE); + } + write ++; + } + } + } + + /* ISIS - Hello Multiplier */ + if (c->hello_multiplier[0] == c->hello_multiplier[1]) { + if (c->hello_multiplier[0] != HELLO_MULTIPLIER ) { + vty_out (vty, " isis hello-multiplier %d%s", + c->hello_multiplier[0], VTY_NEWLINE); + write ++; + } + } else { + for (i=0;i<2;i++) { + if (c->hello_multiplier[i] != HELLO_MULTIPLIER) { + vty_out (vty, " isis hello-multiplier %d level-%d%s", + c->hello_multiplier[i],i+1, VTY_NEWLINE); + write ++; + } + } + } + /* ISIS - Priority */ + if (c->circ_type == CIRCUIT_T_BROADCAST) { + if (c->u.bc.priority[0] == c->u.bc.priority[1]) { + if (c->u.bc.priority[0] != DEFAULT_PRIORITY) { + vty_out (vty, " isis priority %d%s", c->u.bc.priority[0], + VTY_NEWLINE); + write ++; + } + } else { + for (i=0;i<2;i++) { + if (c->u.bc.priority[i] != DEFAULT_PRIORITY) { + vty_out (vty, " isis priority %d level-%d%s", + c->u.bc.priority[i],i+1, VTY_NEWLINE); + write ++; + } + } + } + } + /* ISIS - Metric */ + if (c->metrics[0].metric_default == c->metrics[1].metric_default) { + if (c->metrics[0].metric_default != DEFAULT_CIRCUIT_METRICS) { + vty_out (vty, " isis metric %d%s", c->metrics[0].metric_default, + VTY_NEWLINE); + write ++; + } + } else { + for (i=0;i<2;i++) { + if (c->metrics[i].metric_default != DEFAULT_CIRCUIT_METRICS) { + vty_out (vty, " isis metric %d level-%d%s", + c->metrics[i].metric_default,i+1, VTY_NEWLINE); + write ++; + } + } + } + + } + } + } + + 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 *c; + struct interface *ifp; + struct isis_area *area; + + ifp = (struct interface *)vty->index; + assert (ifp); + + area = isis_area_lookup (argv[0]); + + /* Prevent more than one circuit per interface */ + if (area) + c = circuit_lookup_by_ifp (ifp, area->circuit_list); + else c = NULL; + if (c && (ifp->info != NULL)) { +#ifdef HAVE_IPV6 + if (c->ipv6_router == 0) { +#endif /* HAVE_IPV6 */ + vty_out (vty, "ISIS circuit is already defined%s", VTY_NEWLINE); + return CMD_WARNING; +#ifdef HAVE_IPV6 + } +#endif /* HAVE_IPV6 */ + } + + /* this is here for ciscopability */ + if (!area) { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!c) { + c = circuit_lookup_by_ifp (ifp, isis->init_circ_list); + c = isis_csm_state_change (ISIS_ENABLE, c, area); + c->interface = ifp; /* this is automatic */ + ifp->info = c; /* hardly related to the FSM */ + } + + if(!c) + return CMD_WARNING; + + c->ip_router = 1; + area->ip_circuits++; + circuit_update_nlpids (c); + + vty->node = INTERFACE_NODE; + + 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 isis_circuit *circuit = NULL; + struct interface *ifp; + struct isis_area *area; + struct listnode *node; + + ifp = (struct interface *)vty->index; + assert (ifp); + + area = isis_area_lookup (argv[0]); + if (!area) { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_WARNING; + } + LIST_LOOP (area->circuit_list, circuit, node) + if (circuit->interface == ifp) + break; + if (!circuit) { + vty_out (vty, "Can't find ISIS interface %s", VTY_NEWLINE); + return CMD_WARNING; + } + 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; +} + +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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int circuit_t; + int is_type; + + ifp = vty->index; + circuit = ifp->info; + /* UGLY - will remove l8r */ + if (circuit == NULL) { + return CMD_WARNING; + } + + assert (circuit); + + circuit_t = string2circuit_t (argv[0]); + + if (!circuit_t) { + vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + is_type = circuit->area->is_type; + if (is_type == IS_LEVEL_1_AND_2 || is_type == circuit_t) + isis_event_circuit_type_change (circuit, circuit_t); + else { + vty_out (vty, "invalid circuit level for area %s.%s", + circuit->area->area_tag, VTY_NEWLINE); + } + + 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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + + assert(circuit); + + /* + * Set the circuits level to its default value which is that of the area + */ + isis_event_circuit_type_change (circuit, circuit->area->is_type); + + return CMD_SUCCESS; +} + +DEFUN (isis_passwd, + isis_passwd_cmd, + "isis password WORD", + "IS-IS commands\n" + "Configure the authentication password for interface\n" + "Password\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + int len; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + + len = strlen (argv[0]); + if (len > 254) { + vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); + return CMD_WARNING; + } + circuit->passwd.len = len; + circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; + strncpy (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 interface\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + + 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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int prio; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + prio = atoi (argv[0]); + + circuit->u.bc.priority[0] = prio; + circuit->u.bc.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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->u.bc.priority[0] = DEFAULT_PRIORITY; + circuit->u.bc.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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int prio; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + prio = atoi (argv[0]); + + circuit->u.bc.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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->u.bc.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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int prio; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + prio = atoi (argv[0]); + + circuit->u.bc.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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->u.bc.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-63>", + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int met; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + met = atoi (argv[0]); + + circuit->metrics[0].metric_default = met; + circuit->metrics[1].metric_default = met; + + return CMD_SUCCESS; +} + +DEFUN (no_isis_metric, + no_isis_metric_cmd, + "no isis metric", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRICS; + circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRICS; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_metric, + no_isis_metric_arg_cmd, + "no isis metric <0-127>", + NO_STR + "IS-IS commands\n" + "Set default metric for circuit\n" + "Default metric value\n" + ) +/* end of metrics */ + + +DEFUN (isis_hello_interval, + isis_hello_interval_cmd, + "isis hello-interval (<1-65535>|minimal)", + "IS-IS commands\n" + "Set Hello interval\n" + "Hello interval value\n" + "Holdtime 1 seconds, interval depends on multiplier\n" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int interval; + char c; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + c = *argv[0]; + if (isdigit((int)c)) { + interval = atoi (argv[0]); + } else + interval = HELLO_MINIMAL; /* FIXME: should be calculated */ + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + + circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */ + circuit->hello_interval[1] = HELLO_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval, + no_isis_hello_interval_arg_cmd, + "no isis hello-interval (<1-65535>|minimal)", + 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-65535>|minimal) 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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + long interval; + char c; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + c = *argv[0]; + if (isdigit((int)c)) { + interval = atoi (argv[0]); + } else + interval = HELLO_MINIMAL; + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + + circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */ + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval_l1, + no_isis_hello_interval_l1_arg_cmd, + "no isis hello-interval (<1-65535>|minimal) 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-65535>|minimal) 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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + long interval; + char c; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + c = *argv[0]; + if (isdigit((int)c)) { + interval = atoi (argv[0]); + } else + interval = HELLO_MINIMAL; + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + + circuit->hello_interval[1] = HELLO_INTERVAL; /* Default is 1 sec. */ + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_interval_l2, + no_isis_hello_interval_l2_arg_cmd, + "no isis hello-interval (<1-65535>|minimal) 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 <3-1000>", + "IS-IS commands\n" + "Set multiplier for Hello holding time\n" + "Hello multiplier value\n" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int mult; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + mult = atoi (argv[0]); + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->hello_multiplier[0] = HELLO_MULTIPLIER; + circuit->hello_multiplier[1] = HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier, + no_isis_hello_multiplier_arg_cmd, + "no isis hello-multiplier <3-1000>", + 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 <3-1000> 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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int mult; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + mult = atoi (argv[0]); + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->hello_multiplier[0] = HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier_l1, + no_isis_hello_multiplier_l1_arg_cmd, + "no isis hello-multiplier <3-1000> 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 <3-1000> 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" + ) +{ + struct isis_circuit *circuit; + struct interface *ifp; + int mult; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + mult = atoi (argv[0]); + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->hello_multiplier[1] = HELLO_MULTIPLIER; + + return CMD_SUCCESS; +} + +ALIAS (no_isis_hello_multiplier_l2, + no_isis_hello_multiplier_l2_arg_cmd, + "no isis hello-multiplier <3-1000> 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, + isis_hello_cmd, + "isis hello padding", + "IS-IS commands\n" + "Add padding to IS-IS hello packets\n" + "Pad hello packets\n" + "<cr>\n") +{ + struct interface *ifp; + struct isis_circuit *circuit; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->u.bc.pad_hellos = 1; + + return CMD_SUCCESS; +} + +DEFUN (ip_address, + ip_address_cmd, + "ip address A.B.C.D/A", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8\n") + +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct prefix_ipv4 *ipv4, *ip; + struct listnode *node; + int ret, found = 1; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + + assert (circuit); +#ifdef HAVE_IPV6 + zlog_info ("ip_address_cmd circuit %d", circuit->interface->ifindex); +#endif /* HAVE_IPV6 */ + + ipv4 = prefix_ipv4_new (); + + ret = str2prefix_ipv4 (argv[0], ipv4); + if (ret <= 0) { + zlog_warn ("ip_address_cmd(): malformed address"); + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!circuit->ip_addrs) + circuit->ip_addrs = list_new (); + else { + for (node = listhead (circuit->ip_addrs); node; nextnode (node)) { + ip = getdata (node); + if (prefix_same ((struct prefix *)ip, (struct prefix *)ipv4)) + found = 1; + } + if (found) { + prefix_ipv4_free (ipv4); + return CMD_SUCCESS; + } + } + + + listnode_add (circuit->ip_addrs, ipv4); +#ifdef EXTREME_DEBUG + zlog_info ("added IP address %s to circuit %d", argv[0], + circuit->interface->ifindex); +#endif /* EXTREME_DEBUG */ + return CMD_SUCCESS; +} + +DEFUN (no_ip_address, + no_ip_address_cmd, + "no ip address A.B.C.D/A", + 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") +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct prefix_ipv4 ipv4, *ip = NULL; + struct listnode *node; + int ret; + + ifp = vty->index; + circuit = ifp->info; + /* UGLY - will remove l8r */ + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + if (!circuit->ip_addrs || circuit->ip_addrs->count == 0) { + vty_out (vty, "Invalid address %s", VTY_NEWLINE); + return CMD_WARNING; + } + ret = str2prefix_ipv4 (argv[0], &ipv4); + if (ret <= 0) { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (node = listhead (circuit->ip_addrs); node; nextnode (node)) { + ip = getdata (node); + if (prefix_same ((struct prefix *)ip, (struct prefix *)&ipv4)) + break; + } + + if (ip) { + listnode_delete (circuit->ip_addrs, ip); + } else { + vty_out (vty, "Invalid address %s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN (no_isis_hello, + no_isis_hello_cmd, + "no isis hello padding", + NO_STR + "IS-IS commands\n" + "Add padding to IS-IS hello packets\n" + "Pad hello packets\n" + "<cr>\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->u.bc.pad_hellos = 0; + + return CMD_SUCCESS; +} + +DEFUN (csnp_interval, + csnp_interval_cmd, + "isis csnp-interval <0-65535>", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + unsigned long interval; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + interval = atol (argv[0]); + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->csnp_interval[0] = CSNP_INTERVAL; + circuit->csnp_interval[1] = CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval, + no_csnp_interval_arg_cmd, + "no isis csnp-interval <0-65535>", + 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 <0-65535> level-1", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-1 CSNPs\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + unsigned long interval; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + interval = atol (argv[0]); + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->csnp_interval[0] = CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval_l1, + no_csnp_interval_l1_arg_cmd, + "no isis csnp-interval <0-65535> 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 <0-65535> level-2", + "IS-IS commands\n" + "Set CSNP interval in seconds\n" + "CSNP interval value\n" + "Specify interval for level-2 CSNPs\n") +{ + struct isis_circuit *circuit; + struct interface *ifp; + unsigned long interval; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + interval = atol (argv[0]); + + 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; + struct interface *ifp; + + ifp = vty->index; + circuit = ifp->info; + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + circuit->csnp_interval[1] = CSNP_INTERVAL; + + return CMD_SUCCESS; +} + +ALIAS (no_csnp_interval_l2, + no_csnp_interval_l2_arg_cmd, + "no isis csnp-interval <0-65535> 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") + + +#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 *c; + struct interface *ifp; + struct isis_area *area; + + ifp = (struct interface *)vty->index; + assert (ifp); + + area = isis_area_lookup (argv[0]); + + /* Prevent more than one circuit per interface */ + if (area) + c = circuit_lookup_by_ifp (ifp, area->circuit_list); + else c = NULL; + + if (c && (ifp->info != NULL)) { + if (c->ipv6_router == 1) { + vty_out (vty, "ISIS circuit is already defined for IPv6%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* this is here for ciscopability */ + if (!area) { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!c) { + c = circuit_lookup_by_ifp (ifp, isis->init_circ_list); + c = isis_csm_state_change (ISIS_ENABLE, c, area); + c->interface = ifp; + ifp->info = c; + } + + if(!c) + return CMD_WARNING; + + c->ipv6_router = 1; + area->ipv6_circuits++; + circuit_update_nlpids (c); + + vty->node = INTERFACE_NODE; + + 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 isis_circuit *c; + struct interface *ifp; + struct isis_area *area; + + ifp = (struct interface *)vty->index; + /* UGLY - will remove l8r + if (circuit == NULL) { + return CMD_WARNING; + } */ + assert (ifp); + + area = isis_area_lookup (argv[0]); + if (!area) { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_WARNING; + } + + c = circuit_lookup_by_ifp (ifp, area->circuit_list); + if (!c) + return CMD_WARNING; + + c->ipv6_router = 0; + area->ipv6_circuits--; + if (c->ip_router == 0) + isis_csm_state_change (ISIS_DISABLE, c, area); + + return CMD_SUCCESS; +} + +#if 0 /* Guess we don't really need these */ + +DEFUN (ipv6_address, + ipv6_address_cmd, + "ipv6 address X:X::X:X/M", + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct prefix_ipv6 *ipv6, *ip6; + struct listnode *node; + int ret, found = 1; + + ifp = vty->index; + circuit = ifp->info; + /* UGLY - will remove l8r */ + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); +#ifdef EXTREME_DEBUG + zlog_info ("ipv6_address_cmd circuit %d", circuit->idx); +#endif /* EXTREME_DEBUG */ + + if (circuit == NULL) { + zlog_warn ("ipv6_address_cmd(): no circuit"); + return CMD_WARNING; + } + + + ipv6 = prefix_ipv6_new (); + + ret = str2prefix_ipv6 (argv[0], ipv6); + if (ret <= 0) { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!circuit->ipv6_addrs) + circuit->ipv6_addrs = list_new (); + else { + for (node = listhead (circuit->ipv6_addrs); node; nextnode (node)) { + ip6 = getdata (node); + if (prefix_same ((struct prefix *)ip6, (struct prefix *)ipv6)) + found = 1; + } + if (found) { + prefix_ipv6_free (ipv6); + return CMD_SUCCESS; + } + } + + + listnode_add (circuit->ipv6_addrs, ipv6); +#ifdef EXTREME_DEBUG + zlog_info ("added IPv6 address %s to circuit %d", argv[0], circuit->idx); +#endif /* EXTREME_DEBUG */ + + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_address, + no_ipv6_address_cmd, + "no ipv6 address X:X::X:X/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + struct interface *ifp; + struct isis_circuit *circuit; + struct prefix_ipv6 ipv6, *ip6 = NULL; + struct listnode *node; + int ret; + + ifp = vty->index; + circuit = ifp->info; + /* UGLY - will remove l8r */ + if (circuit == NULL) { + return CMD_WARNING; + } + assert (circuit); + + if (!circuit->ipv6_addrs || circuit->ipv6_addrs->count == 0) { + vty_out (vty, "Invalid address %s", VTY_NEWLINE); + return CMD_WARNING; + } + ret = str2prefix_ipv6 (argv[0], &ipv6); + if (ret <= 0) { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (node = listhead (circuit->ipv6_addrs); node; nextnode (node)) { + ip6 = getdata (node); + if (prefix_same ((struct prefix *)ip6, (struct prefix *)&ipv6)) + break; + } + + if (ip6) { + listnode_delete (circuit->ipv6_addrs, ip6); + } else { + vty_out (vty, "Invalid address %s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} +#endif /* 0 */ +#endif /* HAVE_IPV6 */ + + +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1, +}; + + +int +isis_if_new_hook (struct interface *ifp) +{ +/* FIXME: Discuss if the circuit should be created here + ifp->info = XMALLOC (MTYPE_ISIS_IF_INFO, sizeof (struct isis_if_info)); */ + ifp->info = NULL; + return 0; +} + +int +isis_if_delete_hook (struct interface *ifp) +{ +/* FIXME: Discuss if the circuit should be created here + XFREE (MTYPE_ISIS_IF_INFO, ifp->info);*/ + ifp->info = NULL; + 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_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_circuit_type_cmd); + install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); + + install_element (INTERFACE_NODE, &isis_passwd_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_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_cmd); + install_element (INTERFACE_NODE, &no_isis_hello_cmd); + + install_element (INTERFACE_NODE, &ip_address_cmd); + install_element (INTERFACE_NODE, &no_ip_address_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); + +#ifdef HAVE_IPV6 + install_element (INTERFACE_NODE, &ipv6_router_isis_cmd); + install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd); +#if 0 + install_element (INTERFACE_NODE, &ipv6_address_cmd); + install_element (INTERFACE_NODE, &no_ipv6_address_cmd); +#endif +#endif + +} diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h new file mode 100644 index 00000000..7163c5b9 --- /dev/null +++ b/isisd/isis_circuit.h @@ -0,0 +1,158 @@ +/* + * 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 */ + int pad_hellos; /* add padding to Hello PDUs ? */ + u_char priority[2]; /* l1/2 IS Priority */ +}; + +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 */ + 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) */ + /* 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_BROADCAST 0 +#define CIRCUIT_T_P2P 1 +#define CIRCUIT_T_STATIC_IN 2 +#define CIRCUIT_T_STATIC_OUT 3 +#define CIRCUIT_T_DA 4 + int circ_type; /* type of the physical interface */ + union { + struct isis_bcast_info bc; + struct isis_p2p_info p2p; + } u; + char ext_domain; /* externalDomain (boolean) */ + /* + * Configurables + */ + struct isis_passwd passwd; /* Circuit rx/tx password */ + long lsp_interval; + int manual_l2_only; /* manualL2OnlyMode (boolean) */ + int circuit_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 */ + struct password *c_rx_passwds; /* circuitReceivePasswords */ + struct password *c_tc_passwd; /* circuitTransmitPassword */ + int ip_router; /* Route IP ? */ + 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 */ + /* + * RFC 2973 IS-IS Mesh Groups + */ +#define MESH_INACTIVE 0 +#define MESH_BLOCKED 1 +#define MESH_SET 2 + int mesh_enabled; /* meshGroupEnabled */ + u_int16_t mesh_group; /* meshGroup */ + u_int16_t upadjcount[2]; + /* + * 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); +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_del (struct isis_circuit *circuit); +void isis_circuit_configure (struct isis_circuit *circuit, + struct isis_area *area); +void isis_circuit_up (struct isis_circuit *circuit); +void isis_circuit_deconfigure (struct isis_circuit *circuit, + struct isis_area *area); + +int isis_circuit_destroy (struct isis_circuit *circuit); +void isis_circuit_if_add (struct isis_circuit *circuit, + struct interface *ifp); +void isis_circuit_if_del (struct isis_circuit *circuit); +void circuit_update_nlpids (struct isis_circuit *circuit); +void isis_circuit_update_params (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); +#endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_common.h b/isisd/isis_common.h new file mode 100644 index 00000000..951e6371 --- /dev/null +++ b/isisd/isis_common.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/* + * 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_PRIVATE 255 + u_char type; + 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 ? */ +}; + +/* + * Flags structure for SSN and SRM flags + */ +struct flags { + int maxindex; + struct list *free_idcs; +}; diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h new file mode 100644 index 00000000..c5b59aa3 --- /dev/null +++ b/isisd/isis_constants.h @@ -0,0 +1,151 @@ +/* + * 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_LINK_METRIC 63 +#define MAX_PATH_METRIC 1023 +#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 25 /* % */ +#define MAX_AGE_JITTER 5 /* % */ +#define MAX_LSP_GEN_JITTER 5 /* % */ +#define CSNP_JITTER 10 /* % */ +#define PSNP_JITTER 10 /* % */ + +#define RANDOM_SPREAD 100000.0 + +/* + * Default values + * ISO - 10589 + * Section 7.3.21 - Parameters + */ +#define MAX_AGE 1200 +#define ZERO_AGE_LIFETIME 60 +#define MAX_LSP_GEN_INTERVAL 900 +#define MIN_LSP_GEN_INTERVAL 30 +#define MIN_LSP_TRANS_INTERVAL 5 +#define ISIS_MIN_LSP_LIFETIME 380 +#define CSNP_INTERVAL 10 +#define PSNP_INTERVAL 2 +#define ISIS_MAX_PATH_SPLITS 3 + +#define ISIS_LEVELS 2 +#define ISIS_LEVEL1 1 +#define ISIS_LEVEL2 2 + +#define HELLO_INTERVAL 1 +#define HELLO_MINIMAL HELLO_INTERVAL +#define HELLO_MULTIPLIER 3 +#define DEFAULT_PRIORITY 64 +/* different vendors implement different values 5-10 on average */ +#define LSP_GEN_INTERVAL_DEFAULT 10 +#define LSP_INTERVAL 33 /* msecs */ +#define DEFAULT_CIRCUIT_METRICS 10 +#define METRICS_UNSUPPORTED 0x80 +#define PERIODIC_SPF_INTERVAL 60 /* at the top of my head */ +#define MINIMUM_SPF_INTERVAL 5 /* .. same here */ + +/* + * NLPID values + */ +#define NLPID_IP 204 +#define NLPID_IPV6 142 + +/* + * 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 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) \ + (C->circ_type==CIRCUIT_T_BROADCAST) ? \ + (C->interface->mtu - LLC_LEN) : (C->interface->mtu) + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +#endif /* ISIS_CONSTANTS_H */ + + + + + + + + diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c new file mode 100644 index 00000000..2282bbc8 --- /dev/null +++ b/isisd/isis_csm.c @@ -0,0 +1,186 @@ +/* + * 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 <zebra.h> +#include <net/ethernet.h> + +#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_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/isis_flags.h" +#include "isisd/isisd.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_events.h" + +extern struct isis *isis; + +static char *csm_statestr[] = +{ + "C_STATE_NA", + "C_STATE_INIT", + "C_STATE_CONF", + "C_STATE_UP" +}; + +#define STATE2STR(S) csm_statestr[S] + +static 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; + + zlog_info ("CSM_EVENT: %s", EVENT2STR(event)); + + switch (old_state) { + case C_STATE_NA: + if (circuit) + zlog_warn ("Non-null circuit while state C_STATE_NA"); + 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"); + case IF_DOWN_FROM_Z: + zlog_warn ("circuit already disconnected"); + break; + } + break; + case C_STATE_INIT: + switch (event) { + case ISIS_ENABLE: + isis_circuit_configure (circuit, (struct isis_area *)arg); + isis_circuit_up (circuit); + circuit->state = C_STATE_UP; + isis_event_circuit_state_change (circuit, 1); + listnode_delete (isis->init_circ_list, circuit); + break; + case IF_UP_FROM_Z: + 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); + listnode_delete (isis->init_circ_list, circuit); + isis_circuit_del (circuit); + break; + } + break; + case C_STATE_CONF: + switch (event) { + case ISIS_ENABLE: + zlog_warn ("circuit already enabled"); + break; + case IF_UP_FROM_Z: + isis_circuit_if_add (circuit, (struct interface *)arg); + isis_circuit_up (circuit); + circuit->state = C_STATE_UP; + isis_event_circuit_state_change (circuit, 1); + break; + case ISIS_DISABLE: + isis_circuit_deconfigure (circuit, (struct isis_area *)arg); + isis_circuit_del (circuit); + break; + case IF_DOWN_FROM_Z: + zlog_warn ("circuit already disconnected"); + break; + } + break; + case C_STATE_UP: + 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_deconfigure (circuit, (struct isis_area *)arg); + listnode_add (isis->init_circ_list, circuit); + circuit->state = C_STATE_INIT; + isis_event_circuit_state_change (circuit, 0); + break; + case IF_DOWN_FROM_Z: + isis_circuit_if_del (circuit); + circuit->state = C_STATE_CONF; + isis_event_circuit_state_change (circuit, 0); + break; + } + break; + + default: + zlog_warn ("Invalid circuit state %d", old_state); + } + + zlog_info ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state), + circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA)); + + return circuit; +} + + + diff --git a/isisd/isis_csm.h b/isisd/isis_csm.h new file mode 100644 index 00000000..23cc2150 --- /dev/null +++ b/isisd/isis_csm.h @@ -0,0 +1,47 @@ +/* + * 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 */ diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c new file mode 100644 index 00000000..5b7d23e6 --- /dev/null +++ b/isisd/isis_dr.c @@ -0,0 +1,373 @@ +/* + * 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 <zebra.h> +#include <net/ethernet.h> + +#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" + +extern struct isis *isis; +extern struct thread_master *master; + +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.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.run_dr_elect[1] = 1; + + return ISIS_OK; +} + +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->u.bc.priority[level - 1]; + adjdb = circuit->u.bc.adjdb[level - 1]; + + if (!adjdb) { + zlog_warn ("isis_dr_elect() adjdb == NULL"); + retval = ISIS_WARNING; + list_delete (list); + goto out; + } + isis_adj_build_up_list (adjdb, list); + + /* + * Loop the adjacencies and find the one with the biggest priority + */ + for (node = listhead (list); node; nextnode (node)) { + adj = getdata (node); + /* 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 and thus the DR + */ + if ( !circuit->u.bc.is_dr[level - 1]) { + list_delete (list); + list = NULL; + return isis_dr_commence (circuit, level); + } + goto out; + } + + /* + * 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)) { + if (!circuit->u.bc.is_dr[level - 1]) { + /* + * We are the DR -> commence + */ + list_delete (list); + return 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 (node = listhead (list); node; nextnode (node)) { + adj = getdata (node); + isis_check_dr_change(adj, level); + } + + /* + * We are not DR - if we were -> resign + */ + + if (circuit->u.bc.is_dr[level - 1]) { + list_delete (list); + return isis_dr_resign (circuit, level); + } + } + out: + if (list) + list_delete (list); + return retval; +} + +int +isis_dr_resign (struct isis_circuit *circuit, int level) +{ + u_char id[ISIS_SYS_ID_LEN + 2]; + + zlog_info ("isis_dr_resign l%d", level); + + circuit->u.bc.is_dr[level - 1] = 0; + circuit->u.bc.run_dr_elect[level - 1] = 0; + if (circuit->u.bc.t_run_dr[level - 1]) { + thread_cancel (circuit->u.bc.t_run_dr[level - 1]); + circuit->u.bc.t_run_dr[level - 1] = NULL; + } + if (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]) { + thread_cancel (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); + circuit->u.bc.t_refresh_pseudo_lsp[level - 1] = NULL; + } + + memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(id) = circuit->circuit_id; + LSP_FRAGMENT(id) = 0; + lsp_purge_dr (id, circuit, level); + + if (level == 1) { + memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); + + if (circuit->t_send_csnp[0]) + thread_cancel (circuit->t_send_csnp[0]); + + circuit->u.bc.t_run_dr[0] = + thread_add_timer (master, isis_run_dr_l1, circuit, + 2 * circuit->hello_interval[1]); + + circuit->t_send_psnp[0] = + thread_add_timer (master, + 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); + + if (circuit->t_send_csnp[0]) + thread_cancel (circuit->t_send_csnp[0]); + + circuit->u.bc.t_run_dr[1] = + thread_add_timer (master, isis_run_dr_l2, circuit, + 2 * circuit->hello_interval[1]); + circuit->t_send_psnp[1] = + thread_add_timer (master, + 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]; + + zlog_info ("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) + circuit->u.bc.t_run_dr[0] = + thread_add_timer (master, isis_run_dr_l1, circuit, + 2 * circuit->hello_multiplier[0] * + circuit->hello_interval[0]); + else + circuit->u.bc.t_run_dr[1] = + thread_add_timer (master, isis_run_dr_l2, circuit, + 2 * circuit->hello_multiplier[1] * + 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_dr (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_l1_pseudo_generate (circuit); + + circuit->u.bc.t_run_dr[0] = + thread_add_timer (master, isis_run_dr_l1, circuit, + 2 * circuit->hello_interval[0]); + + circuit->t_send_csnp[0] = thread_add_timer (master, + 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_dr (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_l2_pseudo_generate (circuit); + + circuit->u.bc.t_run_dr[1] = + thread_add_timer (master, isis_run_dr_l2, circuit, + 2 * circuit->hello_interval[1]); + + circuit->t_send_csnp[1] = + thread_add_timer (master, + 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; +} + diff --git a/isisd/isis_dr.h b/isisd/isis_dr.h new file mode 100644 index 00000000..73d9cd38 --- /dev/null +++ b/isisd/isis_dr.h @@ -0,0 +1,42 @@ +/* + * 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); +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 */ + diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c new file mode 100644 index 00000000..9e151d0a --- /dev/null +++ b/isisd/isis_dynhn.c @@ -0,0 +1,124 @@ +/* + * 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 <time.h> +#include <zebra.h> +#include <net/ethernet.h> + +#include "vty.h" +#include "linklist.h" +#include "memory.h" +#include "log.h" +#include "stream.h" +#include "command.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/isisd.h" +#include "isisd/isis_dynhn.h" +#include "isisd/isis_misc.h" +#include "isisd/isis_constants.h" + +extern struct isis *isis; +extern struct host host; + +struct list *dyn_cache = NULL; + +void +dyn_cache_init (void) +{ + dyn_cache = list_new (); + + return; +} + +struct isis_dynhn *dynhn_find_by_id (u_char * id) +{ + struct listnode *node = NULL; + struct isis_dynhn *dyn = NULL; + + for (node = listhead (dyn_cache); node; nextnode (node)) { + dyn = getdata (node); + if (memcmp (dyn->id, id, ISIS_SYS_ID_LEN) == 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 = XMALLOC (MTYPE_ISIS_DYNHN, sizeof (struct isis_dynhn)); + if (!dyn) { + zlog_warn ("isis_dynhn_insert(): out of memory!"); + return; + } + memset (dyn,0,sizeof(struct isis_dynhn)); + /* 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; +} + +/* + * 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 (node = listhead (dyn_cache); node; nextnode (node)) { + dyn = getdata (node); + 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), host.name, + VTY_NEWLINE); + return; +} + diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h new file mode 100644 index 00000000..2a7f3ec9 --- /dev/null +++ b/isisd/isis_dynhn.h @@ -0,0 +1,42 @@ +/* + * 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); +struct isis_dynhn *dynhn_find_by_id (u_char * id); +void dynhn_print_all (struct vty *vty); + +#endif /* _ZEBRA_ISIS_DYNHN_H */ + + + + diff --git a/isisd/isis_events.c b/isisd/isis_events.c new file mode 100644 index 00000000..aada395d --- /dev/null +++ b/isisd/isis_events.c @@ -0,0 +1,336 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <zebra.h> +#include <net/ethernet.h> + +#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_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/isis_flags.h" +#include "isisd/isisd.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_events.h" +#include "isisd/isis_spf.h" + +extern struct thread_master *master; +extern struct isis *isis; + +/* 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, int up) +{ + struct isis_area *area; + + area = circuit->area; + assert (area); + area->circuit_state_changes++; + + if (isis->debugs & DEBUG_EVENTS) + zlog_info ("ISIS-Evt (%s) circuit %s", circuit->area->area_tag, + up ? "up" : "down"); + + /* + * Regenerate LSPs this affects + */ + lsp_regenerate_schedule (area); + + return; +} + +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_info ("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 (area->lspdb[1] == NULL) + area->lspdb[1] = lsp_db_init (); + lsp_l2_generate (area); + break; + case IS_LEVEL_1_AND_2: + if (newtype == IS_LEVEL_1) { + lsp_db_destroy (area->lspdb[1]); + } + else { + lsp_db_destroy (area->lspdb[0]); + } + break; + case IS_LEVEL_2: + if (area->lspdb[0] == NULL) + area->lspdb[0] = lsp_db_init (); + lsp_l1_generate (area); + break; + default: + break; + } + + area->is_type = newtype; + for (node = listhead (area->circuit_list); node; nextnode (node)) { + circuit = getdata (node); + isis_event_circuit_type_change (circuit, newtype); + } + + spftree_area_init (area); + lsp_regenerate_schedule (area); + + return; +} + + + +void +isis_event_area_addr_change (struct isis_area *area) +{ + +} + +void +circuit_commence_level (struct isis_circuit *circuit, int level) +{ + uint32_t interval; + + if (level == 1) { + circuit->t_send_psnp[0] = thread_add_timer (master, send_l1_psnp, + circuit, + isis_jitter + (circuit->psnp_interval[0], + PSNP_JITTER)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + interval = circuit->hello_multiplier[0] * (circuit->hello_interval[0]); + circuit->u.bc.t_run_dr[0] = thread_add_timer (master, isis_run_dr_l1, + circuit, interval); + + circuit->u.bc.t_send_lan_hello[0] = + thread_add_timer (master, + send_lan_l1_hello, + circuit, + isis_jitter + (circuit->hello_interval[0], IIH_JITTER)); + circuit->u.bc.lan_neighs[0] = list_new (); + } + } else { + circuit->t_send_psnp[1] = thread_add_timer (master, send_l2_psnp, + circuit, + isis_jitter + (circuit->psnp_interval[1], + PSNP_JITTER)); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + interval = circuit->hello_multiplier[1] * (circuit->hello_interval[1]); + circuit->u.bc.t_run_dr[1] = thread_add_timer (master, isis_run_dr_l2, + circuit, interval); + + circuit->u.bc.t_send_lan_hello[1] = + thread_add_timer (master, + send_lan_l2_hello, + circuit, + isis_jitter + (circuit->hello_interval[1], IIH_JITTER)); + circuit->u.bc.lan_neighs[1] = list_new (); + } + } + + return; +} + +void +circuit_resign_level (struct isis_circuit *circuit, int level) +{ + int idx = level - 1; + + if (circuit->t_send_csnp[idx]) + thread_cancel (circuit->t_send_csnp[idx]); + circuit->t_send_csnp[idx] = NULL; + + if (circuit->t_send_psnp[idx]) + thread_cancel (circuit->t_send_psnp[idx]); + circuit->t_send_psnp[level - 1] = NULL; + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + if (circuit->u.bc.t_send_lan_hello[idx]) + thread_cancel (circuit->u.bc.t_send_lan_hello[idx]); + circuit->u.bc.t_send_lan_hello[idx] = NULL; + if (circuit->u.bc.t_run_dr[idx]) + thread_cancel (circuit->u.bc.t_run_dr[idx]); + circuit->u.bc.t_run_dr[idx] = NULL; + circuit->u.bc.run_dr_elect[idx] = 0; + } + + return; +} + +void +isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) +{ + + if (isis->debugs & DEBUG_EVENTS) + zlog_info ("ISIS-Evt (%s) circuit type change %s -> %s", + circuit->area->area_tag, + circuit_t2string (circuit->circuit_is_type), + circuit_t2string (newtype)); + + if (circuit->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->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->circuit_is_type = newtype; + lsp_regenerate_schedule (circuit->area); + + 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; + + zlog_info ("ISIS-Evt (%s) Adjacency State change", + adj->circuit->area->area_tag ); + + /* LSP generation again */ + lsp_regenerate_schedule (adj->circuit->area); + + 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; + + zlog_info ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag); + + /* LSP generation again */ + lsp_regenerate_schedule (circuit->area); + + return 0; +} + + +void +isis_event_auth_failure (char *area_tag, char *error_string, char *sysid) +{ + zlog_info ("ISIS-Evt (%s) Authentication failure %s from %s", + area_tag, error_string, sysid_print (sysid)); + + return; +} + diff --git a/isisd/isis_events.h b/isisd/isis_events.h new file mode 100644 index 00000000..75dd92e8 --- /dev/null +++ b/isisd/isis_events.h @@ -0,0 +1,54 @@ +/* + * 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); +void isis_event_area_addr_change (struct isis_area *area); + +/* + * Events related to circuit + */ +void isis_event_circuit_state_change (struct isis_circuit *circuit, 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, char *error_string, char *sysid); + +#endif /* _ZEBRA_ISIS_EVENTS_H */ + diff --git a/isisd/isis_flags.c b/isisd/isis_flags.c new file mode 100644 index 00000000..716bee05 --- /dev/null +++ b/isisd/isis_flags.c @@ -0,0 +1,71 @@ +/* + * 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 <zebra.h> +#include "log.h" +#include "linklist.h" + +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_flags.h" + +int +flags_get_index (struct flags *flags) +{ + struct listnode *node; + int index; + + if (flags->free_idcs == NULL || flags->free_idcs->count == 0) { + flags->maxindex++; + index = flags->maxindex; + } else { + node = listhead (flags->free_idcs); + index = (int) getdata (node); + listnode_delete (flags->free_idcs, (void *)index); + } + + return index; +} + +void +flags_free_index (struct flags *flags, int index) +{ + if (flags->free_idcs == NULL) { + flags->free_idcs = list_new (); + } + + listnode_add (flags->free_idcs, (void *)index); + + 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); +} diff --git a/isisd/isis_flags.h b/isisd/isis_flags.h new file mode 100644 index 00000000..66b94848 --- /dev/null +++ b/isisd/isis_flags.h @@ -0,0 +1,58 @@ +/* + * 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 */ /*FIXME:defined in lsp.h as well*/ + +struct flags *new_flags (int size); +int flags_get_index (struct flags *flags); +void flags_free_index (struct flags *flags, 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 */ + + + + + + diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c new file mode 100644 index 00000000..6bfb0fd4 --- /dev/null +++ b/isisd/isis_lsp.c @@ -0,0 +1,2419 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <zebra.h> +#include <net/ethernet.h> + +#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 "isisd/dict.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.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_flags.h" +#include "isisd/iso_checksum.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_adjacency.h" +#include "isisd/isis_spf.h" + +#ifdef TOPOLOGY_GENERATE +#include "spgrid.h" +#endif + +#define LSP_MEMORY_PREASSIGN + +extern struct isis *isis; +extern struct thread_master *master; +extern struct host host; + +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_warn("searching db"); + for (dn = dict_first(lspdb); dn; dn = dict_next(lspdb, dn)) { + zlog_warn("%s\t%pX", rawlspid_print((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; +} + +void +lsp_clear_data (struct isis_lsp *lsp) +{ + if (!lsp) + return; + + 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.is_neighs) + list_delete (lsp->tlv_data.is_neighs); + if (lsp->tlv_data.area_addrs) + list_delete (lsp->tlv_data.area_addrs); + if (lsp->tlv_data.es_neighs) + list_delete (lsp->tlv_data.es_neighs); + if (lsp->tlv_data.ipv4_addrs) + list_delete (lsp->tlv_data.ipv4_addrs); + if (lsp->tlv_data.ipv4_int_reachs) + list_delete (lsp->tlv_data.ipv4_int_reachs); + if (lsp->tlv_data.ipv4_ext_reachs) + list_delete (lsp->tlv_data.ipv4_ext_reachs); +#ifdef HAVE_IPV6 + if (lsp->tlv_data.ipv6_addrs) + list_delete (lsp->tlv_data.ipv6_addrs); + if (lsp->tlv_data.ipv6_reachs) + list_delete (lsp->tlv_data.ipv6_reachs); +#endif /* HAVE_IPV6 */ + + memset (&lsp->tlv_data, 0, sizeof (struct tlvs)); + + return; +} + +void +lsp_destroy (struct isis_lsp *lsp) +{ + if (!lsp) + return; + + lsp_clear_data (lsp); + + if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) { + list_delete (lsp->lspu.frags); + } + + 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 + */ +void +lsp_remove_frags (struct list *frags, dict_t *lspdb) +{ + dnode_t *dnode; + struct listnode *lnode; + struct isis_lsp *lsp; + + for (lnode = listhead (frags); lnode; nextnode (lnode)) { + lsp = getdata (lnode); + 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_info ("ISIS-Snp (%s): 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_info ("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_info ("ISIS-Snp (%s): 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_info ("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_info ("ISIS-Snp (%s): 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_info ("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; +} + +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 ++; + + lsp->lsp_header->seq_num = htonl (newseq); + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs(lsp->lsp_header->pdu_len) - 12, 12); + + return; +} + +/* + * Genetates checksum for LSP and its frags + */ +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 (node = listhead (lsp0->lspu.frags); node; nextnode (node)) { + lsp = getdata (node); + lsp_inc_seqnum(lsp, 0); + } + + return; +} + +int +isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area, + int pdulen, struct isis_passwd *passwd) +{ + uint32_t expected = 0, found; + struct tlvs tlvs; + int retval = 0; + + expected |= TLVFLAG_AUTH_INFO; + retval = parse_tlvs (area->area_tag, stream->data + + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, + pdulen - ISIS_FIXED_HDR_LEN + - ISIS_LSP_HDR_LEN, + &expected, &found, &tlvs); + if (retval || !(found & TLVFLAG_AUTH_INFO)) + return 1; /* Auth fail (parsing failed or no auth-tlv)*/ + + return authentication_check (passwd, &tlvs.auth_info); +} + +void +lsp_update_data (struct isis_lsp *lsp, struct stream *stream, + struct isis_area *area) +{ + uint32_t expected = 0,found; + int retval; + + /* copying only the relevant part of our stream */ + lsp->pdu = stream_new (stream->endp); + lsp->pdu->putp = stream->putp; + lsp->pdu->getp = stream->getp; + lsp->pdu->endp = stream->endp; + memcpy (lsp->pdu->data, stream->data, stream->endp); + + /* 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->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; + if ((lsp->lsp_header->lsp_bits & 3) == 3) /* a level 2 LSP */ + expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS; + 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, lsp->pdu->data + + 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); + + if (found & TLVFLAG_DYN_HOSTNAME) { + if (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 : + (lsp->lsp_header->lsp_bits & LSPBIT_IST)); + } + +} + +void +lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr, + struct stream *stream, struct isis_area *area) +{ + + /* free the old lsp data*/ + XFREE (MTYPE_STREAM_DATA, lsp->pdu); + lsp_clear_data (lsp); + + /* rebuild the lsp data */ + lsp_update_data (lsp, stream, area); + + /* set the new values for lsp header */ + memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); + +} + + +/* 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) +{ + struct isis_lsp *lsp; + + lsp = XMALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); + memset (lsp, 0, sizeof (struct isis_lsp)); + + lsp_update_data (lsp, stream, area); + + 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 = XMALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); + if (!lsp) { + /* FIXME: set lspdbol bit */ + zlog_warn ("lsp_new(): out of memory"); + return NULL; + } + memset (lsp, 0, sizeof (struct isis_lsp)); +#ifdef LSP_MEMORY_PREASSIGN + lsp->pdu = stream_new (1514); /*Should be minimal mtu? yup...*/ +#else + /* We need to do realloc on TLVs additions*/ + lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); +#endif /* LSP_MEMORY_PREASSIGN */ + 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 == 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_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + + /* #ifdef EXTREME_DEBUG */ + /* logging */ + zlog_info ("New LSP with ID %s-%02x-%02x 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->seq_num)); + /* #endif EXTREME DEBUG */ + + return lsp; +} + +void +lsp_insert (struct isis_lsp *lsp, dict_t *lspdb) +{ + dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp); +} + +/* + * 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 all LSPs bounded by start and stop ids + */ +void +lsp_build_list (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; + + listnode_add (list, first->dict_data); + + while (curr) { + curr = dict_next (lspdb, curr); + if (curr) + listnode_add (list, curr->dict_data); + if (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, struct list *list, + dict_t *lspdb) +{ + dnode_t *dnode, *next; + struct isis_lsp *lsp; + + 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); + dnode = next; + } + + return; +} + +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; + } + + /* If we are turning 0 */ + /* ISO 10589 - 7.3.16.4 first paragraph */ + + if (ntohs (lsp->lsp_header->rem_lifetime) == 1) { + /* 7.3.16.4 a) set SRM flags on all */ + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + /* 7.3.16.4 b) retain only the header FIXME */ + /* 7.3.16.4 c) record the time to purge FIXME (other way to do it)*/ + } + + lsp->lsp_header->rem_lifetime = + htons (ntohs (lsp->lsp_header->rem_lifetime) - 1); +} + +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 (id, "%.14s", dyn->name.name); + else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost) + sprintf (id, "%.14s", host.name); + else { + memcpy(id, sysid_print (lsp_id), 15); + } + if (frag) + sprintf (trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID(lsp_id), + LSP_FRAGMENT(lsp_id)); + else + sprintf (trg, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id)); +} + +/* Convert the lsp attribute bits to attribute string */ +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 (dnode_t *node, struct vty *vty, char dynhost) +{ + struct isis_lsp *lsp = dnode_get(node); + u_char LSPid[255]; + + lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); + vty_out (vty, "%-21s%c ", LSPid,lsp->own_lsp?'*':' '); + 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) + vty_out (vty, " (%2u)",lsp->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 (dnode_t *node, struct vty *vty, char dynhost) +{ + struct isis_lsp *lsp = dnode_get (node); + struct area_addr *area_addr; + char nlpidstr[2]; + 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; +#endif + u_char LSPid[255]; + u_char hostname[255]; + u_char buff[BUFSIZ]; + u_int32_t now,helper; + 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(node, vty, dynhost); + + /* for all area address */ + if (lsp->tlv_data.area_addrs) { + LIST_LOOP (lsp->tlv_data.area_addrs, area_addr, lnode) { + 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); + } + + if (lsp->tlv_data.ipv4_addrs) { + LIST_LOOP(lsp->tlv_data.ipv4_addrs, ipv4_addr, lnode) { + memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_addr)); + vty_out (vty, " IP: %s%s", + ipv4_address, + VTY_NEWLINE); + } + } + + /* for the internal reachable tlv */ + if (lsp->tlv_data.ipv4_int_reachs) + LIST_LOOP(lsp->tlv_data.ipv4_int_reachs, ipv4_reach, lnode) { + 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, " Matric: %d IP %s %s%s", + ipv4_reach->metrics.metric_default, + ipv4_reach_prefix, + ipv4_reach_mask, + VTY_NEWLINE); + } + + /* for the IS neighbor tlv */ + if (lsp->tlv_data.is_neighs) { + LIST_LOOP(lsp->tlv_data.is_neighs,is_neigh,lnode) { + lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0); + vty_out (vty, " Metric: %d IS %s%s", + is_neigh->metrics.metric_default, + LSPid, + VTY_NEWLINE); + } + } + +/* FIXME: Other tlvs such as te or external tlv will be added later */ +#if 0 + vty_out (vty, "%s %s %c%s", + VTY_NEWLINE, + LSPid, + lsp->own_lsp ? '*' : ' ', + VTY_NEWLINE); + + vty_out (vty, " Sequence: 0x%08x Checksum: 0x%04x Lifetime: ", + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum)); + + if (ntohs (lsp->lsp_header->rem_lifetime) == 0) + vty_out (vty, " (%2u) ", lsp->age_out); + else + vty_out (vty, "%5u ", ntohs (lsp->lsp_header->rem_lifetime)); + + vty_out (vty, "%s Attributes:%s", + VTY_NEWLINE, + lsp_bits2string (&lsp->lsp_header->lsp_bits)); + + /* if this is a self originated LSP then print + * the generation time plus when we sent it last + * if it is a non self-originated LSP then print the + * time when the LSP has been installed + */ + + if (lsp->own_lsp) { + + now = time (NULL); + helper = now - lsp->last_generated; + if (!lsp->last_generated) + helper = 0; + + vty_out (vty, ", Generated: %s ago", + time2string (helper)); + + now = time (NULL); + helper = now - lsp->last_sent; + if (!lsp->last_sent) + helper = 0; + + vty_out (vty, ", Last sent: %s ago", + time2string (helper)); + } else { + now = time (NULL); + helper = now - lsp->installed; + if (!lsp->installed) + helper = 0; + + vty_out (vty, ", Installed: %s ago", + time2string (helper)); + + } + + vty_out (vty, "%s", VTY_NEWLINE); + + if (lsp->tlv_data.nlpids) { + vty_out (vty, " Speaks: %s%s", nlpid2string (lsp->tlv_data.nlpids), + VTY_NEWLINE); + } + + if (lsp->tlv_data.router_id) { + vty_out (vty, " Router ID: %s%s", + inet_ntoa (lsp->tlv_data.router_id->id), VTY_NEWLINE); + } + + if (lsp->tlv_data.is_neighs) + LIST_LOOP(lsp->tlv_data.is_neighs,is_neigh,lnode) { + lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0); + vty_out (vty, " IS %s, Metric: %d%s", + LSPid, + is_neigh->metrics.metric_default, + VTY_NEWLINE); + } + + if (lsp->tlv_data.te_is_neighs) + LIST_LOOP(lsp->tlv_data.te_is_neighs,te_is_neigh,lnode) { + /* FIXME: metric display is wrong */ + lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); + vty_out (vty, " extd-IS %s, Metric: %d%s", + LSPid, + te_is_neigh->te_metric[0], + VTY_NEWLINE); + } + + if (lsp->tlv_data.ipv4_int_reachs) + LIST_LOOP(lsp->tlv_data.ipv4_int_reachs, ipv4_reach, lnode) { + vty_out (vty, " int-IP %s/%d, Metric: %d%s", + inet_ntoa (ipv4_reach->prefix), + ip_masklen (ipv4_reach->mask), + ipv4_reach->metrics.metric_default, + VTY_NEWLINE); + } + + if (lsp->tlv_data.ipv4_ext_reachs) + LIST_LOOP(lsp->tlv_data.ipv4_ext_reachs,ipv4_reach,lnode) { + vty_out (vty, " ext-IP %s/%d, Metric: %d%s", + inet_ntoa(ipv4_reach->prefix), + ip_masklen(ipv4_reach->mask), + ipv4_reach->metrics.metric_default, + VTY_NEWLINE); + } + + if (lsp->tlv_data.te_ipv4_reachs) + LIST_LOOP(lsp->tlv_data.te_ipv4_reachs,te_ipv4_reach,lnode) { + vty_out (vty, " extd-IP %s/%d, Metric: %d%s", + inet_ntoa ( newprefix2inaddr (&te_ipv4_reach->prefix_start, + te_ipv4_reach->control)), + te_ipv4_reach->control & 0x3F, + ntohl (te_ipv4_reach->te_metric), + VTY_NEWLINE); + } + +#ifdef HAVE_IPV6 + if (lsp->tlv_data.ipv6_reachs) + LIST_LOOP(lsp->tlv_data.ipv6_reachs, ipv6_reach, lnode) { + memcpy (in6.s6_addr, ipv6_reach->prefix, 16); + inet_ntop (AF_INET6, &in6, buff, BUFSIZ); + if ((ipv6_reach->control_info && + CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) + vty_out (vty, " int-IPv6 %s/%d, Metric: %d%s", + buff, + ipv6_reach->prefix_len, + ntohl (ipv6_reach->metric), + VTY_NEWLINE); + else + vty_out (vty, " ext-IPv6 %s/%d, Metric: %d%s", + buff, + ipv6_reach->prefix_len, + ntohl (ipv6_reach->metric), + VTY_NEWLINE); + + } +#endif + if (lsp->tlv_data.hostname) { + memset (hostname, 0, sizeof (hostname)); + memcpy (hostname, lsp->tlv_data.hostname->name, + lsp->tlv_data.hostname->namelen); + vty_out (vty, " Hostname: %s%s", hostname, VTY_NEWLINE); + } +#endif + 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; + + /* print the title, for both modes */ + vty_out (vty, "LSP ID LSP Seq Num LSP Checksum " + "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE); + + if (detail == ISIS_UI_LEVEL_BRIEF) { + while (node != NULL) { + /* dict_contains (lspdb, node); */ /* I think it is unnecessary, so I comment it out */ + next = dict_next (lspdb, node); + lsp_print (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 (node, vty, dynhost); + node = next; + lsp_count++; + } + } + + return lsp_count; +} + +/* this function reallocate memory to an lsp pdu, with an additional + * size of memory, it scans the lsp and moves all pointers the + * way they should */ +u_char * +lsppdu_realloc (struct isis_lsp *lsp, int memorytype, int size) +{ + u_char *retval; + + retval = STREAM_DATA(lsp->pdu) + ntohs(lsp->lsp_header->pdu_len); +#ifdef LSP_MEMORY_PREASSIGN + lsp->lsp_header->pdu_len = htons(ntohs(lsp->lsp_header->pdu_len) + size); + return retval; +#else /* otherwise we have to move all pointers */ + u_char *newpdu; + newpdu = stream_new (ntohs (lsp->lsp_header->pdu_len) + size); + memcpy (STREAM_DATA (newpdu), STREAM_DATA(lsp->pdu), + ntohs (lsp->lsp_header->pdu_len)); + XFREE (memorytype, lsp->pdu); + lsp->pdu = newpdu; + 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); + htons (ntohs (lsp->lsp_header->pdu_len) += size); + return STREAM_DATA(lsp->pdu) + (lsp->lsp_header->pdu_len - size); +#endif /* LSP_MEMORY_PREASSIGN */ +} + + +#if 0 /* Saving the old one just in case :) */ +/* + * Builds the lsp->tlv_data + * and writes the tlvs into lsp->pdu + */ +void +lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) +{ + struct is_neigh *is_neigh; + struct listnode *node, *ipnode; + int level = lsp->level; + struct isis_circuit *circuit; + struct prefix_ipv4 *ipv4; + struct ipv4_reachability *ipreach; + struct isis_adjacency *nei; +#ifdef HAVE_IPV6 + struct prefix_ipv6 *ipv6; + struct ipv6_reachability *ip6reach; +#endif /* HAVE_IPV6 */ + + /* + * 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); + /* Protocols Supported */ + if (area->ip_circuits > 0 +#ifdef HAVE_IPV6 + || area->ipv6_circuits > 0 +#endif /* HAVE_IPV6 */ + ) + { + lsp->tlv_data.nlpids = XMALLOC (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 */ + } + /* Dynamic Hostname */ + if (area->dynhostname) { + lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, + sizeof (struct hostname)); + memcpy (&lsp->tlv_data.hostname->name, host.name, strlen(host.name)); + lsp->tlv_data.hostname->namelen = strlen (host.name); + } +#ifdef TOPOLOGY_GENERATE + /* + * If we have a topology in this area, we need to connect this lsp to + * the first topology lsp + */ + if ((area->topology) && (level == 1)) { + if (lsp->tlv_data.is_neighs == NULL) + lsp->tlv_data.is_neighs = list_new (); + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, sizeof (struct is_neigh)); + memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); + /* connected to the first */ + is_neigh->neigh_id[ISIS_SYS_ID_LEN-1] = (0x01); + /* this is actually the same system, why mess the SPT */ + is_neigh->metrics.metric_default = 0; + is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + + } +#endif + + /* + * Then add tlvs related to circuits + */ + for (node = listhead (area->circuit_list); node; nextnode (node)) { + circuit = getdata (node); + 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 (lsp->tlv_data.ipv4_int_reachs == NULL) { + lsp->tlv_data.ipv4_int_reachs = list_new (); + lsp->tlv_data.ipv4_int_reachs->del = free_tlv; + } + for (ipnode = listhead (circuit->ip_addrs); ipnode; nextnode (ipnode)) { + ipv4 = getdata (ipnode); + ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability)); + ipreach->metrics = circuit->metrics[level - 1]; + ipreach->prefix = ipv4->prefix; + masklen2ip (ipv4->prefixlen, &ipreach->mask); + listnode_add (lsp->tlv_data.ipv4_int_reachs, 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 (lsp->tlv_data.ipv6_reachs == NULL) { + lsp->tlv_data.ipv6_reachs = list_new (); + lsp->tlv_data.ipv6_reachs->del = free_tlv; + } + for (ipnode = listhead (circuit->ipv6_non_link); ipnode; + nextnode (ipnode)) { + ipv6 = getdata (ipnode); + ip6reach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability)); + memset (ip6reach, 0, sizeof (struct ipv6_reachability)); + ip6reach->metric = htonl(circuit->metrics[level - 1].metric_default); + ip6reach->control_info = 0; + ip6reach->prefix_len = ipv6->prefixlen; + memcpy (&ip6reach->prefix, ipv6->prefix.s6_addr, + (ipv6->prefixlen + 7) / 8); + listnode_add (lsp->tlv_data.ipv6_reachs, ip6reach); + } + } +#endif /* HAVE_IPV6 */ + + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + if (level & circuit->circuit_is_type) { + if (lsp->tlv_data.is_neighs == NULL) { + lsp->tlv_data.is_neighs = list_new (); + lsp->tlv_data.is_neighs->del = free_tlv; + } + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, sizeof (struct is_neigh)); + if (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]; + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + } + break; + case CIRCUIT_T_P2P: + nei = circuit->u.p2p.neighbor; + if (nei && (level & nei->circuit_t)) { + if (lsp->tlv_data.is_neighs == NULL) { + lsp->tlv_data.is_neighs = list_new (); + lsp->tlv_data.is_neighs->del = free_tlv; + } + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, sizeof (struct is_neigh)); + memcpy (&is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); + is_neigh->metrics = circuit->metrics[level - 1]; + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + } + break; + case CIRCUIT_T_STATIC_IN: + zlog_warn ("lsp_area_create: unsupported circuit type"); + break; + case CIRCUIT_T_STATIC_OUT: + zlog_warn ("lsp_area_create: unsupported circuit type"); + break; + case CIRCUIT_T_DA: + zlog_warn ("lsp_area_create: unsupported circuit type"); + break; + default: + zlog_warn ("lsp_area_create: unknown circuit type"); + } + } + + stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + + 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); + 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.ipv4_int_reachs && + listcount (lsp->tlv_data.ipv4_int_reachs) > 0) + tlv_add_ipv4_reachs (lsp->tlv_data.ipv4_int_reachs, lsp->pdu); +#ifdef HAVE_IPV6 + if (lsp->tlv_data.ipv6_reachs && + listcount (lsp->tlv_data.ipv6_reachs) > 0) + tlv_add_ipv6_reachs (lsp->tlv_data.ipv6_reachs, lsp->pdu); +#endif /* HAVE_IPV6 */ + + lsp->lsp_header->pdu_len = htons (stream_get_putp (lsp->pdu)); + + return; +} +#endif + +#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)) + +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); + *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)); + if (count) + count = count / tlvsize; + for (i = 0; i < count; i++) { + listnode_add (*to, getdata(listhead(*from))); + listnode_delete(*from, getdata(listhead(*from))); + } + tlv_build_func (*to, lsp->pdu); + } + lsp->lsp_header->pdu_len = htons (stream_get_putp (lsp->pdu)); + return; +} + +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; + lsp = lsp_search (frag_id, area->lspdb[level - 1]); + if (lsp) { + /* + * Clear the TLVs, but inherit the authinfo + */ + lsp_clear_data (lsp); + if (lsp0->tlv_data.auth_info.type) { + memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info, + sizeof (struct isis_passwd)); + tlv_add_authinfo (lsp->tlv_data.auth_info.type, + lsp->tlv_data.auth_info.len, + lsp->tlv_data.auth_info.passwd, lsp->pdu); + } + return lsp; + } + lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type, + 0, level); + lsp->own_lsp = 1; + lsp_insert (lsp, area->lspdb[level-1]); + listnode_add (lsp0->lspu.frags, lsp); + lsp->lspu.zero_lsp = lsp0; + /* + * Copy the authinfo from zero LSP + */ + if (lsp0->tlv_data.auth_info.type) { + memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info, + sizeof (struct isis_passwd)); + tlv_add_authinfo (lsp->tlv_data.auth_info.type, + lsp->tlv_data.auth_info.len, + lsp->tlv_data.auth_info.passwd, lsp->pdu); + } + return lsp; +} + +/* + * Builds the LSP data part. This func creates a new frag whenever + * area->lsp_frag_threshold is exceeded. + */ +#if 1 +void +lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) +{ + struct is_neigh *is_neigh; + struct listnode *node, *ipnode; + int level = lsp->level; + struct isis_circuit *circuit; + struct prefix_ipv4 *ipv4; + struct ipv4_reachability *ipreach; + struct isis_adjacency *nei; +#ifdef HAVE_IPV6 + struct prefix_ipv6 *ipv6; + struct ipv6_reachability *ip6reach; +#endif /* HAVE_IPV6 */ + struct tlvs tlv_data; + struct isis_lsp *lsp0 = lsp; + struct isis_passwd *passwd; + + /* + * 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); + /* Protocols Supported */ + if (area->ip_circuits > 0 +#ifdef HAVE_IPV6 + || area->ipv6_circuits > 0 +#endif /* HAVE_IPV6 */ + ) + { + lsp->tlv_data.nlpids = XMALLOC (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 */ + } + /* Dynamic Hostname */ + if (area->dynhostname) { + lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, + sizeof (struct hostname)); + memcpy (lsp->tlv_data.hostname->name, host.name, strlen (host.name)); + lsp->tlv_data.hostname->namelen = strlen (host.name); + } + + /* + * Building the zero lsp + */ + stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + /* + * Add the authentication info if its present + */ + (level == 1) ? (passwd = &area->area_passwd) : + (passwd = &area->domain_passwd); + if (passwd->type) { + memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); + tlv_add_authinfo (passwd->type, passwd->len, + passwd->passwd, lsp->pdu); + } + 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)); + /* + * Then build lists of tlvs related to circuits + */ + for (node = listhead (area->circuit_list); node; nextnode (node)) { + circuit = getdata (node); + 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 (tlv_data.ipv4_int_reachs == NULL) { + tlv_data.ipv4_int_reachs = list_new (); + } + for (ipnode = listhead (circuit->ip_addrs); ipnode; nextnode (ipnode)) { + ipv4 = getdata (ipnode); + ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability)); + ipreach->metrics = circuit->metrics[level - 1]; + ipreach->prefix = ipv4->prefix; + masklen2ip (ipv4->prefixlen, &ipreach->mask); + listnode_add (tlv_data.ipv4_int_reachs, 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 (); + } + for (ipnode = listhead (circuit->ipv6_non_link); ipnode; + nextnode (ipnode)) { + ipv6 = getdata (ipnode); + ip6reach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability)); + memset (ip6reach, 0, sizeof (struct ipv6_reachability)); + ip6reach->metric = htonl(circuit->metrics[level - 1].metric_default); + ip6reach->control_info = 0; + ip6reach->prefix_len = ipv6->prefixlen; + memcpy (ip6reach->prefix, ipv6->prefix.s6_addr, + (ipv6->prefixlen + 7) / 8); + listnode_add (tlv_data.ipv6_reachs, ip6reach); + } + } +#endif /* HAVE_IPV6 */ + + switch (circuit->circ_type) { + case CIRCUIT_T_BROADCAST: + if (level & circuit->circuit_is_type) { + if (tlv_data.is_neighs == NULL) { + tlv_data.is_neighs = list_new (); + } + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, sizeof (struct is_neigh)); + if (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]; + listnode_add (tlv_data.is_neighs, is_neigh); + } + break; + case CIRCUIT_T_P2P: + nei = circuit->u.p2p.neighbor; + if (nei && (level & nei->circuit_t)) { + if (tlv_data.is_neighs == NULL) { + tlv_data.is_neighs = list_new (); + tlv_data.is_neighs->del = free_tlv; + } + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, 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); + } + break; + case CIRCUIT_T_STATIC_IN: + zlog_warn ("lsp_area_create: unsupported circuit type"); + break; + case CIRCUIT_T_STATIC_OUT: + zlog_warn ("lsp_area_create: unsupported circuit type"); + break; + case CIRCUIT_T_DA: + zlog_warn ("lsp_area_create: unsupported circuit type"); + 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); + } + +#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); + } + + + return; +} +#endif + +void +build_lsp_data (struct isis_lsp *lsp, struct isis_area *area) +{ + struct list *circuit_list = area->circuit_list; + struct isis_circuit *circuit; + u_char *tlv_ptr; + struct is_neigh *is_neigh; + + + /* add our nlpids */ + /* the 2 is for the TL plus 1 for the nlpid*/ + tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 3); + *tlv_ptr = PROTOCOLS_SUPPORTED; /* Type */ + *(tlv_ptr+1) = 1; /* one protocol */ +#ifdef HAVE_IPV6 /*dunno if its right*/ + *(tlv_ptr+2) = NLPID_IPV6; +#else + *(tlv_ptr+2) = NLPID_IP; +#endif /* HAVE_IPV6 */ + + /* we should add our areas here + * FIXME: we need to figure out which should be added? Adj? All? First? */ + + /* first, lets add ourselves to the IS neighbours info */ + /* the 2 is for the TL plus 1 for the virtual field*/ + tlv_ptr = lsppdu_realloc(lsp,MTYPE_ISIS_TLV, 3); + *tlv_ptr = IS_NEIGHBOURS; /* Type */ + *(tlv_ptr+2) = 0; /* virtual is zero */ + lsp->tlv_data.is_neighs = list_new (); /* new list of is_neighbours */ + /* assign space for the is_neigh at the pdu end */ + is_neigh = (struct is_neigh*) lsppdu_realloc(lsp,MTYPE_ISIS_TLV, + sizeof(struct is_neigh)); + /* add this node to our list */ + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + /* FIXME: Do we need our designated address here? */ + memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN + 1); + /* FIXME: Where should we really get our own LSPs metrics from? */ + circuit = (struct isis_circuit*)listhead(circuit_list); + /* is_neigh->metrics = circuit->metrics[lsp->level -1];*/ + /* Length */ + *(tlv_ptr+1)=(lsp->tlv_data.is_neighs->count * sizeof(struct is_neigh) +1); + + /* FIXME: scan for adjencecies and add them */ + + /* FIXME: add reachability info */ + + /* adding dynamic hostname if needed*/ + if (area->dynhostname) { + tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 2); /* the 2 is for the TL */ + *tlv_ptr = DYNAMIC_HOSTNAME; /* Type */ + *(tlv_ptr+1) = strlen (host.name); /* Length */ + lsp->tlv_data.hostname = (struct hostname *) + (lsppdu_realloc(lsp, + MTYPE_ISIS_TLV, + /* the -1 is to fit the length in the struct */ + strlen (host.name)) - 1); + memcpy (lsp->tlv_data.hostname->name, host.name, strlen(host.name)); + } + +} + +/* + * 7.3.7 Generation on non-pseudonode LSPs + */ +int +lsp_generate_non_pseudo (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]; + + 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 */ + if ((area->is_type & level) == level) { + oldlsp = lsp_search (lspid, area->lspdb[level-1]); + if (oldlsp) { + seq_num = ntohl (oldlsp->lsp_header->seq_num); + lsp_search_and_destroy (oldlsp->lsp_header->lsp_id, + area->lspdb[level-1]); + /* FIXME: we should actually initiate a purge */ + } + newlsp = lsp_new (lspid, area->max_lsp_lifetime[level-1], seq_num, + area->is_type, 0, level); + newlsp->own_lsp = 1; + + lsp_insert (newlsp, area->lspdb[level-1]); + /* build_lsp_data (newlsp, area); */ + lsp_build_nonpseudo (newlsp, area); + /* time to calculate our checksum */ + lsp_seqnum_update (newlsp); + } + + + /* DEBUG_ADJ_PACKETS */ + if (isis->debugs & DEBUG_ADJ_PACKETS) { + /* FIXME: is this place right? fix missing info */ + zlog_info ("ISIS-Upd (%s): Building L%d LSP", + area->area_tag, level); + } + + return ISIS_OK; +} + +/* + * 7.3.9 Generation of level 1 LSPs (non-pseudonode) + */ +int +lsp_l1_generate (struct isis_area *area) +{ + + area->t_lsp_refresh[0] = thread_add_timer (master, lsp_refresh_l1, area, + MAX_LSP_GEN_INTERVAL); + + return lsp_generate_non_pseudo (area, 1); +} + + +/* + * 7.3.9 Generation of level 2 LSPs (non-pseudonode) + */ +int +lsp_l2_generate (struct isis_area *area) +{ + + area->t_lsp_refresh[1] = thread_add_timer (master, lsp_refresh_l2, area, + MAX_LSP_GEN_INTERVAL); + + return lsp_generate_non_pseudo (area, 2); +} + +int +lsp_non_pseudo_regenerate (struct isis_area *area, int level) +{ + dict_t *lspdb = area->lspdb[level - 1]; + struct isis_lsp *lsp, *frag; + struct listnode *node; + u_char lspid[ISIS_SYS_ID_LEN + 2]; + + 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_non_pseudo_regenerate(): no L%d LSP found!", + area->area_tag, + level); + + return ISIS_ERROR; + } + + lsp_clear_data (lsp); + lsp_build_nonpseudo (lsp, area); + lsp->lsp_header->rem_lifetime = htons (isis_jitter + (area->max_lsp_lifetime[level-1], + MAX_AGE_JITTER)); + lsp_seqnum_update (lsp); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_info ("ISIS-Upd (%s): refreshing our L%d LSP %s, " + "seq 0x%08x, cksum 0x%04x lifetime %us", + area->area_tag, + 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)); + } + + lsp->last_generated = time (NULL); + area->lsp_regenerate_pending[level - 1] = 0; + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + for (node = listhead (lsp->lspu.frags); node; nextnode(node)) { + frag = getdata (node); + frag->lsp_header->rem_lifetime = htons (isis_jitter + (area->max_lsp_lifetime[level-1], + MAX_AGE_JITTER)); + ISIS_FLAGS_SET_ALL (frag->SRMflags); + } + + if (area->ip_circuits) + isis_spf_schedule (area, level); +#ifdef HAVE_IPV6 + if (area->ipv6_circuits) + isis_spf_schedule6 (area, level); +#endif + return ISIS_OK; +} + + +/* + * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding + * time and set SRM + */ +int +lsp_refresh_l1 (struct thread *thread) +{ + struct isis_area *area; + unsigned long ref_time; + + area = THREAD_ARG (thread); + assert (area); + + area->t_lsp_refresh[0] = NULL; + if (area->is_type & IS_LEVEL_1) + lsp_non_pseudo_regenerate (area, 1); + + ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? + MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0]; + + area->t_lsp_refresh[0] = thread_add_timer (master, lsp_refresh_l1, area, + isis_jitter (ref_time, + MAX_AGE_JITTER)); + return ISIS_OK; +} + +int +lsp_refresh_l2 (struct thread *thread) +{ + struct isis_area *area; + unsigned long ref_time; + + area = THREAD_ARG (thread); + assert (area); + + area->t_lsp_refresh[1] = NULL; + if (area->is_type & IS_LEVEL_2) + lsp_non_pseudo_regenerate (area, 2); + + ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? + MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1]; + + + area->t_lsp_refresh[1] = thread_add_timer (master, lsp_refresh_l2, area, + isis_jitter (ref_time, + MAX_AGE_JITTER)); + return ISIS_OK; +} + + +/* + * Something has changed -> regenerate LSP + */ + +int +lsp_l1_regenerate (struct thread *thread) +{ + struct isis_area *area; + + area = THREAD_ARG (thread); + area->lsp_regenerate_pending[0] = 0; + + return lsp_non_pseudo_regenerate (area, 1); +} + +int +lsp_l2_regenerate (struct thread *thread) +{ + struct isis_area *area; + + area = THREAD_ARG (thread); + area->lsp_regenerate_pending[1] = 0; + + return lsp_non_pseudo_regenerate (area, 2); +} + +int +lsp_regenerate_schedule (struct isis_area *area) +{ + struct isis_lsp *lsp; + u_char id[ISIS_SYS_ID_LEN + 2]; + time_t now, diff; + memcpy(id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0; + now = time (NULL); + /* + * First level 1 + */ + if (area->is_type & IS_LEVEL_1) { + lsp = lsp_search (id, area->lspdb[0]); + if (!lsp || area->lsp_regenerate_pending[0]) + goto L2; + /* + * Throttle avoidance + */ + diff = now - lsp->last_generated; + if (diff < MIN_LSP_GEN_INTERVAL) { + area->lsp_regenerate_pending[0] = 1; + thread_add_timer (master, lsp_l1_regenerate, area, + MIN_LSP_GEN_INTERVAL - diff); + return ISIS_OK; + } else + lsp_non_pseudo_regenerate (area, 1); + } + /* + * then 2 + */ + L2: + if (area->is_type & IS_LEVEL_2) { + lsp = lsp_search (id, area->lspdb[1]); + if (!lsp || area->lsp_regenerate_pending[1]) + return ISIS_OK; + /* + * Throttle avoidance + */ + diff = now - lsp->last_generated; + if (diff < MIN_LSP_GEN_INTERVAL) { + area->lsp_regenerate_pending[1] = 1; + thread_add_timer (master, lsp_l2_regenerate, area, + MIN_LSP_GEN_INTERVAL - diff); + return ISIS_OK; + } else + lsp_non_pseudo_regenerate (area, 2); + } + + return ISIS_OK; +} + +/* + * Funcs for pseudonode LSPs + */ + +/* + * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs + */ +void +lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, + int level) +{ + struct isis_adjacency *adj; + struct is_neigh *is_neigh; + struct es_neigh *es_neigh; + struct list *adj_list; + struct listnode *node; + struct isis_passwd *passwd; + + assert (circuit); + assert (circuit->circ_type == CIRCUIT_T_BROADCAST); + + if (!circuit->u.bc.is_dr[level - 1]) + return; /* we are not DIS on this circuit */ + + lsp->level = level; + if (level == 1) + lsp->lsp_header->lsp_bits |= IS_LEVEL_1; + else + lsp->lsp_header->lsp_bits |= IS_LEVEL_2; + + /* + * add self to IS neighbours + */ + if (lsp->tlv_data.is_neighs == NULL) { + lsp->tlv_data.is_neighs = list_new (); + lsp->tlv_data.is_neighs->del = free_tlv; + } + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, sizeof (struct is_neigh)); + memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + + adj_list = list_new(); + isis_adj_build_up_list (circuit->u.bc.adjdb[level-1], adj_list); + + for (node = listhead (adj_list); node; nextnode (node)){ + adj = getdata (node); + if (adj->circuit_t & level) { + if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) || + (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS && + adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || + (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) { + /* an IS neighbour -> add it */ + is_neigh = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); + memset (is_neigh, 0, sizeof (struct is_neigh)); + memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + } else if (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 = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh)); + memset (es_neigh, 0, sizeof (struct es_neigh)); + memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN); + listnode_add (lsp->tlv_data.es_neighs, is_neigh); + } + } + } + + stream_set_putp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + /* + * Add the authentication info if it's present + */ + (level == 1) ? (passwd = &circuit->area->area_passwd) : + (passwd = &circuit->area->domain_passwd); + if (passwd->type) { + memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); + tlv_add_authinfo (passwd->type, passwd->len, + passwd->passwd, lsp->pdu); + } + + 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.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_putp (lsp->pdu)); + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs(lsp->lsp_header->pdu_len) - 12, 12); + + list_delete (adj_list); + + return; +} + +int +lsp_pseudo_regenerate (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]; + + 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_pseudo_regenerate(): no l%d LSP %s found!", level, + rawlspid_print(lsp_id)); + return ISIS_ERROR; + } + lsp_clear_data (lsp); + + lsp_build_pseudo (lsp, circuit, level); + + lsp->lsp_header->rem_lifetime = + htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1], + MAX_AGE_JITTER)); + + lsp_inc_seqnum (lsp, 0); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_info ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s", + circuit->area->area_tag, level, + rawlspid_print (lsp->lsp_header->lsp_id)); + } + + lsp->last_generated = time (NULL); + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + + return ISIS_OK; +} + + +int +lsp_l1_refresh_pseudo (struct thread *thread) +{ + struct isis_circuit *circuit; + int retval; + unsigned long ref_time; + + circuit = THREAD_ARG(thread); + + if (!circuit->u.bc.is_dr[0]) + return ISIS_ERROR; /* FIXME: purge and such */ + + retval = lsp_pseudo_regenerate (circuit, 1); + + ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? + MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0]; + + circuit->u.bc.t_refresh_pseudo_lsp[0] = + thread_add_timer (master, lsp_l1_refresh_pseudo, circuit, + isis_jitter (ref_time, + MAX_AGE_JITTER)); + return retval; +} + +int +lsp_l1_pseudo_generate (struct isis_circuit *circuit) +{ + struct isis_lsp *lsp; + u_char id[ISIS_SYS_ID_LEN + 2]; + unsigned long ref_time; + + memcpy(id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_FRAGMENT(id) = 0; + LSP_PSEUDO_ID(id) = circuit->circuit_id; + + /* + * If for some reason have a pseudo LSP in the db already -> regenerate + */ + if (lsp_search (id, circuit->area->lspdb[0])) + return lsp_pseudo_regenerate (circuit, 1); + lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0], + 1, circuit->area->is_type, 0, 1); + + lsp_build_pseudo (lsp, circuit, 1); + + lsp->own_lsp = 1; + lsp_insert (lsp, circuit->area->lspdb[0]); + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + + ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? + MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0]; + + + circuit->u.bc.t_refresh_pseudo_lsp[0] = + thread_add_timer (master, lsp_l1_refresh_pseudo, circuit, + isis_jitter (ref_time, + MAX_AGE_JITTER)); + + return lsp_regenerate_schedule (circuit->area); +} + +int +lsp_l2_refresh_pseudo (struct thread *thread) +{ + struct isis_circuit *circuit; + int retval; + unsigned long ref_time; + circuit = THREAD_ARG(thread); + + if (!circuit->u.bc.is_dr[1]) + return ISIS_ERROR; /* FIXME: purge and such */ + + retval = lsp_pseudo_regenerate (circuit, 2); + + ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? + MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1]; + + + circuit->u.bc.t_refresh_pseudo_lsp[1] = + thread_add_timer (master, lsp_l2_refresh_pseudo, circuit, + isis_jitter (ref_time, + MAX_AGE_JITTER)); + return retval; +} + + +int +lsp_l2_pseudo_generate (struct isis_circuit *circuit) +{ + struct isis_lsp *lsp; + u_char id[ISIS_SYS_ID_LEN + 2]; + unsigned long ref_time; + + memcpy(id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_FRAGMENT(id) = 0; + LSP_PSEUDO_ID(id) = circuit->circuit_id; + + if (lsp_search (id, circuit->area->lspdb[1])) + return lsp_pseudo_regenerate (circuit, 2); + + lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1], + 1, circuit->area->is_type, 0, 2); + + lsp_build_pseudo (lsp, circuit, 2); + + ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? + MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1]; + + + lsp->own_lsp = 1; + lsp_insert (lsp, circuit->area->lspdb[1]); + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + + circuit->u.bc.t_refresh_pseudo_lsp[1] = + thread_add_timer (master, lsp_l2_refresh_pseudo, circuit, + isis_jitter (ref_time, + MAX_AGE_JITTER)); + + return lsp_regenerate_schedule (circuit->area); +} + + + +/* + * 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; + + lsp_list = list_new (); + + area = THREAD_ARG (thread); + assert (area); + area->t_tick = thread_add_timer (master, 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) { + dnode = dict_first (area->lspdb[level]); + while (dnode != NULL) { + dnode_next = dict_next (area->lspdb[level], dnode); + lsp = dnode_get (dnode); + lsp_set_time (lsp); + if (lsp->age_out == 0) { + + zlog_info ("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)); + + lsp_destroy (lsp); + dict_delete (area->lspdb[level], dnode); + } else if (flags_any_set (lsp->SRMflags)) + listnode_add (lsp_list, lsp); + dnode = dnode_next; + } + + /* + * Send LSPs on circuits indicated by the SRMflags + */ + if (listcount (lsp_list) > 0) { + for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode)) { + circuit = getdata (cnode); + for (lspnode = listhead (lsp_list); lspnode; nextnode (lspnode)) { + lsp = getdata (lspnode); + if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) { + /* FIXME: if same or elder lsp is already in lsp queue */ + 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_dr (u_char *id, struct isis_circuit *circuit, int level) +{ + struct isis_lsp *lsp; + + lsp = lsp_search (id, circuit->area->lspdb[level - 1]); + + if (lsp && lsp->purged == 0) { + lsp->lsp_header->rem_lifetime = htons (0); + lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + lsp->purged = 0; + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs(lsp->lsp_header->pdu_len) - 12, 12); + ISIS_FLAGS_SET_ALL(lsp->SRMflags); + } + + + 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 + */ + zlog_info ("LSP PURGE NON EXIST"); + lsp = XMALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); + memset (lsp, 0, sizeof (struct isis_lsp)); + /*FIXME: BUG BUG BUG! the lsp doesn't exist here!*/ + /*did smt here, maybe good probably not*/ + lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2; + lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + lsp->isis_header = (struct isis_fixed_hdr*)STREAM_DATA(lsp->pdu); + fill_fixed_hdr (lsp->isis_header, (lsp->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); + + /* + * Retain only LSP header + */ + lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + /* + * Set the remaining lifetime to 0 + */ + lsp->lsp_header->rem_lifetime = 0; + /* + * Put the lsp into LSPdb + */ + lsp_insert (lsp, area->lspdb[lsp->level-1]); + + /* + * Send in to whole area + */ + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + + return; +} + +#ifdef TOPOLOGY_GENERATE +int +top_lsp_refresh (struct thread *thread) +{ + struct isis_lsp *lsp; + + lsp = THREAD_ARG (thread); + assert (lsp); + + lsp->t_lsp_top_ref = NULL; + + lsp->lsp_header->rem_lifetime = htons (isis_jitter(MAX_AGE,MAX_AGE_JITTER)); + lsp->lsp_header->seq_num = htonl(ntohl(lsp->lsp_header->seq_num) +1); + + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_info ("ISIS-Upd (): refreshing Topology L1 %s", + rawlspid_print (lsp->lsp_header->lsp_id)); + } + + /* time to calculate our checksum */ + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs(lsp->lsp_header->pdu_len) - 12, 12); + + lsp->t_lsp_top_ref = thread_add_timer (master, top_lsp_refresh, lsp, + isis_jitter (MAX_LSP_GEN_INTERVAL, + MAX_LSP_GEN_JITTER)); + + 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; + + /* first we find the maximal node */ + LIST_LOOP (area->topology, arc, node) { + 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); + + lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0], + MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1); + lsp->from_topology = 1; + /* creating data based on topology */ + build_topology_lsp_data (lsp,area,i); + /* time to calculate our checksum */ + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs(lsp->lsp_header->pdu_len) - 12, 12); + lsp->t_lsp_top_ref = thread_add_timer (master, top_lsp_refresh, lsp, + isis_jitter(MAX_LSP_GEN_INTERVAL, + MAX_LSP_GEN_JITTER)); + + ISIS_FLAGS_SET_ALL(lsp->SRMflags); + 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_cancel(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; + u_char *tlv_ptr; + struct is_neigh *is_neigh; + int to_lsp = 0; + char buff[200]; + + /* add our nlpids */ + /* the 2 is for the TL plus 1 for the nlpid*/ + tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 3); + *tlv_ptr = PROTOCOLS_SUPPORTED; /* Type */ + *(tlv_ptr+1) = 1; /* one protocol */ + *(tlv_ptr+2) = NLPID_IP; + lsp->tlv_data.nlpids = (struct nlpids*)(tlv_ptr+1); + + /* first, lets add the tops */ + /* the 2 is for the TL plus 1 for the virtual field*/ + tlv_ptr = lsppdu_realloc (lsp ,MTYPE_ISIS_TLV, 3); + *tlv_ptr = IS_NEIGHBOURS; /* Type */ + *(tlv_ptr+1) = 1; /* this is the virtual char len*/ + *(tlv_ptr+2) = 0; /* virtual is zero */ + lsp->tlv_data.is_neighs = list_new (); /* new list of is_neighbours */ + + /* add reachability for this IS for simulated 1 */ + if (lsp_top_num == 1) { + /* assign space for the is_neigh at the pdu end */ + is_neigh = (struct is_neigh*) lsppdu_realloc(lsp, MTYPE_ISIS_TLV, + sizeof(struct is_neigh)); + /* add this node to our list */ + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00; + is_neigh->metrics.metric_default = 0x00; /* no special reason */ + is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; + is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; + /* don't forget the length */ + *(tlv_ptr+1) += IS_NEIGHBOURS_LEN; /* the -1 is the virtual */ + /* no need to check for fragging here, it is a lonely is_reach */ + } + + /* addding is reachabilities */ + LIST_LOOP (area->topology, arc, node) { + if ((arc->from_node == lsp_top_num) || + (arc->to_node == lsp_top_num)) { + if (arc->to_node == lsp_top_num) to_lsp = arc->from_node; + if (arc->from_node == lsp_top_num) to_lsp = arc->to_node; + + /* if the length here is about to cross the FF limit, we reTLV */ + if (*(tlv_ptr+1) >= (0xFF - IS_NEIGHBOURS_LEN)) { + /* retlv */ + /* the 2 is for the TL plus 1 for the virtual field*/ + tlv_ptr = lsppdu_realloc(lsp,MTYPE_ISIS_TLV, 3); + *tlv_ptr = IS_NEIGHBOURS; /* Type */ + *(tlv_ptr+1) = 1; /* this is the virtual char len*/ + *(tlv_ptr+2) = 0; /* virtual is zero */ + } + /* doing this here assures us that we won't add an "empty" tlv */ + /* assign space for the is_neigh at the pdu end */ + is_neigh = (struct is_neigh*) lsppdu_realloc (lsp, MTYPE_ISIS_TLV, + sizeof(struct is_neigh)); + /* add this node to our list */ + listnode_add (lsp->tlv_data.is_neighs, is_neigh); + memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00; + 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; + /* don't forget the length */ + *(tlv_ptr+1) += IS_NEIGHBOURS_LEN; /* the -1 is the virtual */ + } + } + + /* adding dynamic hostname if needed*/ + if (area->dynhostname) { + memset (buff,0x00,200); + sprintf (buff,"feedme%d",lsp_top_num); + tlv_ptr = lsppdu_realloc (lsp,MTYPE_ISIS_TLV, 2); /* the 2 is for the TL */ + *tlv_ptr = DYNAMIC_HOSTNAME; /* Type */ + *(tlv_ptr+1) = strlen (buff); /* Length */ + /* the -1 is to fit the length in the struct */ + lsp->tlv_data.hostname = (struct hostname *) + (lsppdu_realloc (lsp, MTYPE_ISIS_TLV, strlen(buff)) - 1); + memcpy (lsp->tlv_data.hostname->name, buff, strlen(buff)); + } + + /* thanks to hannes, another bug bites the dust */ + lsp->pdu->putp = ntohs(lsp->lsp_header->pdu_len); + lsp->pdu->endp = ntohs(lsp->lsp_header->pdu_len); +} +#endif /* TOPOLOGY_GENERATE */ diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h new file mode 100644 index 00000000..71a75089 --- /dev/null +++ b/isisd/isis_lsp.h @@ -0,0 +1,132 @@ +/* + * 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 + +/* 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 */ /*FIXME:defined in flags.h as well*/ + +/* 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 SRMflags[ISIS_MAX_CIRCUITS]; + u_int32_t SSNflags[ISIS_MAX_CIRCUITS]; + u_int32_t rexmit_queue[ISIS_MAX_CIRCUITS]; + int level; /* L1 or L2? */ + int purged; /* have purged this one */ + int scheduled; /* scheduled for sending */ + time_t installed; + time_t last_generated; + time_t last_sent; + 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_adjacency *adj; + 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_l1_generate (struct isis_area *area); +int lsp_l2_generate (struct isis_area *area); +int lsp_refresh_l1 (struct thread *thread); +int lsp_refresh_l2 (struct thread *thread); +int lsp_regenerate_schedule (struct isis_area *area); + +int lsp_l1_pseudo_generate (struct isis_circuit *circuit); +int lsp_l2_pseudo_generate (struct isis_circuit *circuit); +int lsp_l1_refresh_pseudo (struct thread *thread); +int lsp_l2_refresh_pseudo (struct thread *thread); +int isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area, + int pdulen, struct isis_passwd *passwd); +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); +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, + 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, struct list *list, + dict_t *lspdb); + +void lsp_search_and_destroy (u_char *id, dict_t *lspdb); +void lsp_purge_dr (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) ((u_char)(I)[ISIS_SYS_ID_LEN]) +#define LSP_FRAGMENT(I) ((u_char)(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 isis_link_state_hdr *lsp_hdr, + struct stream *stream, struct isis_area *area); +void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num); +int lsp_print_all (struct vty *vty, dict_t *lspdb, char detail, char dynhost); +char *lsp_bits2string (u_char *); + +/* staticly assigned vars for printing purposes */ +char lsp_bits_string[200]; /* FIXME: enough ? */ + +#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 */ + diff --git a/isisd/isis_main.c b/isisd/isis_main.c new file mode 100644 index 00000000..baf5f38d --- /dev/null +++ b/isisd/isis_main.c @@ -0,0 +1,330 @@ +/* + * 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 <stdio.h> +#include <zebra.h> +#include <net/ethernet.h> + +#include "getopt.h" +#include "thread.h" +#include "log.h" +#include "version.h" +#include "command.h" +#include "vty.h" +#include "memory.h" +#include "stream.h" +#include "if.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" + +/* Default configuration file name */ +#define ISISD_DEFAULT_CONFIG "isisd.conf" +/* Default vty port */ +#define ISISD_VTY_PORT 2607 + +/* isisd options */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "vty_port", required_argument, NULL, 'P'}, + { "version", no_argument, NULL, 'v'}, + { "help", no_argument, NULL, 'h'}, + { 0 } +}; + +/* Configuration file and directory. */ +char config_current[] = ISISD_DEFAULT_CONFIG; +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; + + +/* for reload */ +char _cwd[64]; +char _progpath[64]; +int _argc; +char **_argv; +char **_envp; + + +/* 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\ +-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 sambo@cs.tut.fi\n", progname); + } + + exit (status); +} + + +void +reload () +{ + zlog_info ("Reload"); + /* FIXME: Clean up func call here */ + vty_finish (); + execve (_progpath, _argv, _envp); +} + +void +terminate (int i) +{ + exit (i); +} + +/* + * Signal handlers + */ +void +sighup (int sig) +{ + zlog_info ("SIGHUP received"); + reload (); + + return; +} + +void +sigint (int sig) +{ + zlog_info ("SIGINT received"); + terminate (0); + + return; +} + +void +sigterm (int sig) +{ + zlog_info ("SIGTERM received"); + terminate (0); +} + +void +sigusr1 (int sig) +{ + zlog_info ("SIGUSR1 received"); + zlog_rotate (NULL); +} + +/* + * Signal wrapper. + */ +RETSIGTYPE * +signal_set (int signo, void (*func)(int)) +{ + int ret; + struct sigaction sig; + struct sigaction osig; + + sig.sa_handler = func; + sigemptyset (&sig.sa_mask); + sig.sa_flags = 0; +#ifdef SA_RESTART + sig.sa_flags |= SA_RESTART; +#endif /* SA_RESTART */ + + ret = sigaction (signo, &sig, &osig); + + if (ret < 0) + return (SIG_ERR); + else + return (osig.sa_handler); +} + +void +signal_init () +{ + signal_set (SIGHUP, sighup); + signal_set (SIGINT, sigint); + signal_set (SIGTERM, sigterm); + signal_set (SIGPIPE, SIG_IGN); +#ifdef SIGTSTP + signal_set (SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTIN + signal_set (SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTTOU + signal_set (SIGTTOU, SIG_IGN); +#endif + signal_set (SIGUSR1, sigusr1); +} + +/* + * Main routine of 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; + + /* Get the programname without the preceding path. */ + progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); + + zlog_default = openzlog (progname, ZLOG_NOLOG, 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:hAp:P:v", longopts, 0); + + if (opt == EOF) + break; + + switch (opt) + { + case 0: + break; + case 'd': + daemon_mode = 1; + break; + case 'f': + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'P': + vty_port = atoi (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 'h': + usage (0); + break; + default: + usage (1); + break; + } + } + + /* thread master */ + master = thread_master_create (); + + /* random seed from time */ + srand(time(NULL)); + + /* + * initializations + */ + signal_init (); + cmd_init (1); + vty_init (); + memory_init (); + isis_init (); + dyn_cache_init (); + sort_node (); + + /* parse config file */ + /* this is needed three times! because we have interfaces before the areas */ + vty_read_config (config_file, config_current, config_default); +#if 0 + vty_read_config (config_file, config_current, config_default); + vty_read_config (config_file, config_current, config_default); +#endif + /* demonize */ + if (daemon_mode) + daemon (0, 0); + + /* Problems with the build env ?*/ +#ifndef PATH_ISISD_PID +#define PATH_ISISD_PID "/var/run/isisd.pid" +#endif + /* Process ID file creation. */ + pid_output (PATH_ISISD_PID); + + /* Make isis vty socket. */ + vty_serv_sock (vty_addr, vty_port ? vty_port : ISISD_VTY_PORT, + ISIS_VTYSH_PATH); + + /* Print banner. */ + zlog_info ("ISISd %s starting: vty@%d", ZEBRA_VERSION, vty_port); +#ifdef HAVE_IPV6 + zlog_info ("IPv6 enabled"); +#endif + /* Start finite state machine. */ + while (thread_fetch (master, &thread)) + thread_call (&thread); + + /* Not reached. */ + exit (0); +} + + + + + + + + + + diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c new file mode 100644 index 00000000..763ae243 --- /dev/null +++ b/isisd/isis_misc.c @@ -0,0 +1,438 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <ctype.h> +#include <zebra.h> +#include <net/ethernet.h> + + +#include "stream.h" +#include "vty.h" +#include "hash.h" +#include "if.h" + +#include "isisd/dict.h" +#include "isisd/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_circuit.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" + +/* + * This converts the isonet to its printable format + */ +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 == 0) { /* if the area addr is just one byte, eg. 47. */ + 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, u_char *dotted) +{ + int dotlen, len = 0; + u_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(number, NULL, 16); + len++; + } + + return len; +} +/* + * conversion of XXXX.XXXX.XXXX to memory + */ +int +sysid2buff (u_char *buff, u_char *dotted) + { + int len = 0; + u_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(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; + 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 (u_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_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 + */ +char * +snpa_print (u_char *from) +{ + int i = 0; + u_char *pos = snpa; + + if(!from) + return "unknown"; + + while (i < ETH_ALEN - 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 snpa; +} + +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; +} + +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; +} + +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; +} + + + + + diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h new file mode 100644 index 00000000..0e219c65 --- /dev/null +++ b/isisd/isis_misc.h @@ -0,0 +1,94 @@ +/* + * 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 dotformat2buff (u_char *, u_char *); +int string2circuit_t (u_char *); +const char *circuit_t2string (int); +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 *, u_char *); +int sysid2buff (u_char *, u_char *); + +/* + * Printing functions + */ +char *isonet_print (u_char *, int len); +char *sysid_print (u_char *); +char *snpa_print (u_char *); +char *rawlspid_print (u_char *); +char *time2string (u_int32_t); +/* typedef struct nlpids nlpids; */ +char *nlpid2string (struct nlpids *); + + +/* + * misc functions + */ +int speaks (struct nlpids *nlpids, int family); +unsigned long isis_jitter (unsigned long timer, unsigned long jitter); + +/* + * macros + */ +#define GETSYSID(A,L) (A->area_addr + (A->addr_len - (L + 1))) + + +/* 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]; + +/* 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 diff --git a/isisd/isis_network.c b/isisd/isis_network.c new file mode 100644 index 00000000..d22f3dd8 --- /dev/null +++ b/isisd/isis_network.c @@ -0,0 +1,622 @@ +/* + * IS-IS Rout(e)ing protocol - isis_network.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 <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <zebra.h> +#include <net/ethernet.h> /* the L2 protocols */ + +#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" + +/* + * On linux we can use the packet(7) sockets, in other OSs we have to do with + * Berkley Packet Filter (BPF). Please tell me if you can think of a better + * way... + */ +#ifdef GNU_LINUX +#include <netpacket/packet.h> +#else +#include <sys/time.h> +#include <sys/ioctl.h> +#include <net/bpf.h> +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) +}; +int readblen = 0; +u_char *readbuff = NULL; +#endif /* GNU_LINUX */ + +/* + * Table 9 - Architectural constans 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}; + +#ifdef GNU_LINUX +static char discard_buff[8192]; +#endif +static char sock_buff[8192]; + +/* + * if level is 0 we are joining p2p multicast + * FIXME: and the p2p multicast being ??? + */ +#ifdef GNU_LINUX +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_info ("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", strerror (errno)); + return ISIS_WARNING; + } + + return ISIS_OK; +} + +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", 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", strerror(errno)); + return ISIS_WARNING; + } + + circuit->fd = fd; + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + /* + * Join to multicast groups + * according to + * 8.4.2 - Broadcast subnetwork IIH PDUs + * FIXME: is there a case only one will fail?? + */ + if (circuit->circuit_is_type & IS_LEVEL_1) { + /* joining ALL_L1_ISS */ + retval = isis_multicast_join (circuit->fd, 1, + circuit->interface->ifindex); + /* joining ALL_ISS */ + retval = isis_multicast_join (circuit->fd, 3, + circuit->interface->ifindex); + } + if (circuit->circuit_is_type & IS_LEVEL_2) + /* joining ALL_L2_ISS */ + retval = isis_multicast_join (circuit->fd, 2, + circuit->interface->ifindex); + } else { + retval = isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex); + } + + return retval; +} + +#else + +int +open_bpf_dev (struct isis_circuit *circuit) +{ + int i = 0, fd; + char bpfdev[128]; + struct ifreq ifr; + u_int16_t blen; + int true = 1, false = 0; + 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", + strerror (errno)); + return ISIS_WARNING; + } + + zlog_info ("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", + 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_info ("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. + */ + if (ioctl (fd, BIOCIMMEDIATE, (caddr_t)&true) < 0) { + zlog_warn ("failed to set BPF dev to immediate mode"); + } + + /* + * We want to see only incoming packets + */ + if (ioctl (fd, BIOCSSEESENT, (caddr_t)&false) < 0) { + zlog_warn ("failed to set BPF dev to incoming only mode"); + } + + /* + * ...but all of them + */ + if (ioctl (fd, BIOCPROMISC, (caddr_t)&true) < 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", + strerror (errno)); + return ISIS_WARNING; + } + + + assert (fd > 0); + + circuit->fd = fd; + + return ISIS_OK; +} + +#endif /* GNU_LINUX */ + +/* + * Create the socket and set the tx/rx funcs + */ +int +isis_sock_init (struct isis_circuit *circuit) +{ + int retval = ISIS_OK; + + +#ifdef GNU_LINUX + retval = open_packet_socket (circuit); +#else + retval = open_bpf_dev (circuit); +#endif + + if (retval == ISIS_OK) { + 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; + } + } + + 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; +} + +#ifdef GNU_LINUX +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, &addr_len); + + if (bytesread < 0) { + zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s", + circuit->fd, strerror (errno)); + zlog_warn ("circuit is %s", circuit->interface->name); + zlog_warn ("circuit fd %d", circuit->fd); + zlog_warn ("bytesread %d", bytesread); + /* get rid of the packet */ + bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff)); + 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 = read (circuit->fd, discard_buff, sizeof (discard_buff)); + if (bytesread < 0) + zlog_warn ("isis_recv_pdu_bcast(): read() failed"); + return ISIS_WARNING; + } + + /* on lan we have to read to the static buff first */ + bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0, + (struct sockaddr *)&s_addr, &addr_len); + + /* then we lose the LLC */ + memcpy (STREAM_DATA (circuit->rcv_stream), + sock_buff + LLC_LEN, bytesread - LLC_LEN); + circuit->rcv_stream->putp = bytesread - LLC_LEN; + circuit->rcv_stream->endp = 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 = recvfrom (circuit->fd, STREAM_DATA (circuit->rcv_stream), + circuit->interface->mtu, 0, + (struct sockaddr *)&s_addr, &addr_len); + + if(s_addr.sll_pkttype == PACKET_OUTGOING) { + /* Read the packet into discard buff */ + bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff)); + if (bytesread < 0) + zlog_warn ("isis_recv_pdu_p2p(): read() failed"); + return ISIS_WARNING; + } + + circuit->rcv_stream->putp = bytesread; + circuit->rcv_stream->endp = bytesread; + + /* 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) +{ + /* 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; + 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; + + /* then we copy the data */ + memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, + stream_get_endp (circuit->snd_stream)); + + /* now we can send this */ + written = sendto (circuit->fd, sock_buff, + circuit->snd_stream->putp + LLC_LEN, 0, + (struct sockaddr *)&sa, sizeof (struct sockaddr_ll)); + + + 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, + circuit->snd_stream->putp, 0, (struct sockaddr *)&sa, + sizeof (struct sockaddr_ll)); + + return ISIS_OK; +} + + +#else + +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", strerror (errno)); + } + + if (bytestoread) { + bytesread = read (circuit->fd, readbuff, readblen); + } + if (bytesread < 0) { + zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s", 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 */ + memcpy (STREAM_DATA (circuit->rcv_stream), + readbuff + offset, + bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN); + + circuit->rcv_stream->putp = bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN; + circuit->rcv_stream->endp = bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN; + circuit->rcv_stream->getp = 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", strerror (errno)); + + return ISIS_OK; +} + +int +isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char *ssnpa) +{ + int bytesread; + + bytesread = read (circuit->fd, STREAM_DATA(circuit->rcv_stream), + circuit->interface->mtu); + + if (bytesread < 0) { + zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", strerror (errno)); + return ISIS_WARNING; + } + + circuit->rcv_stream->putp = bytesread; + circuit->rcv_stream->endp = bytesread; + + return ISIS_OK; +} + + + +int +isis_send_pdu_bcast (struct isis_circuit *circuit, int level) +{ + struct ether_header *eth; + int written; + + 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, + circuit->snd_stream->putp + LLC_LEN + ETHER_HDR_LEN); + + + return ISIS_OK; +} + +int +isis_send_pdu_p2p (struct isis_circuit *circuit, int level) +{ + + + return ISIS_OK; +} + + + + +#endif /* GNU_LINUX */ + + + + + diff --git a/isisd/isis_network.h b/isisd/isis_network.h new file mode 100644 index 00000000..7633f9e0 --- /dev/null +++ b/isisd/isis_network.h @@ -0,0 +1,37 @@ +/* + * 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 */ diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c new file mode 100644 index 00000000..8d636b30 --- /dev/null +++ b/isisd/isis_pdu.c @@ -0,0 +1,2478 @@ +/* + * 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 <stdio.h> +#include <string.h> +#include <zebra.h> +#include <net/ethernet.h> + +#include "memory.h" +#include "thread.h" +#include "linklist.h" +#include "log.h" +#include "stream.h" +#include "vty.h" +#include "hash.c" +#include "prefix.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_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_flags.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" + +extern struct thread_master *master; +extern struct isis *isis; + +#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; + + LIST_LOOP (left, addr1, node1) { + LIST_LOOP (right, addr2, node2) { + 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 + */ +int +ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2) +{ + u_char *addr1, *addr2; + int shift, offset; + int len; + + addr1 = (u_char *) &ip1->prefix.s_addr; + addr2 = (u_char *) &ip2->s_addr; + len = ip1->prefixlen; + + shift = len % PNBBY; + offset = len / PNBBY; + + while (offset--) { + if (addr1[offset] != addr2[offset]) { + 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; + + LIST_LOOP (left, ip1, node1) { + LIST_LOOP (right, ip2, node2) { + 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; +} + +int +authentication_check (struct isis_passwd *one, struct isis_passwd *theother) +{ + if (one->type != theother->type) { + zlog_warn ("Unsupported authentication type %d", theother->type ); + return 1; /* Auth fail (different authentication types)*/ + } + switch (one->type) { + case ISIS_PASSWD_TYPE_CLEARTXT: + if (one->len != theother->len) + return 1; /* Auth fail () - passwd len mismatch */ + return memcmp (one->passwd, theother->passwd, one->len); + break; + default: + zlog_warn ("Unsupported authentication type"); + break; + } + return 0; /* Auth pass */ +} + +/* + * Processing helper functions + */ +void +tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) +{ + int i; + struct nlpids *tlv_nlpids; + + if (tlvs->nlpids) { + + tlv_nlpids = tlvs->nlpids; + + adj->nlpids.count = tlv_nlpids->count; + + for (i=0;i<tlv_nlpids->count;i++) { + adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; + } + } +} + +void +del_ip_addr (void *val) +{ + XFREE (MTYPE_ISIS_TMP, val); +} + +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_ip_addr; + list_delete (adj->ipv4_addrs); + } + adj->ipv4_addrs = list_new (); + if (tlvs->ipv4_addrs) { + LIST_LOOP (tlvs->ipv4_addrs, ipv4_addr, node) { + 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 +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_ip_addr; + list_delete (adj->ipv6_addrs); + } + adj->ipv6_addrs = list_new (); + if (tlvs->ipv6_addrs) { + LIST_LOOP (tlvs->ipv6_addrs, ipv6_addr, node) { + 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; + struct tlvs tlvs; + + 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); + circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN; + + /* hdr.circuit_t = stream_getc (stream); + stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN); + hdr.hold_time = stream_getw (stream); + hdr.pdu_len = stream_getw (stream); + hdr.local_id = stream_getc (stream); */ + + /* + * My interpertation of the ISO, if no adj exists we will create one for + * the circuit + */ + + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_info("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->circuit_is_type), + circuit->circuit_id,ntohs(hdr->pdu_len)); + } + + adj = circuit->u.p2p.neighbor; + if ( !adj ) { + adj = isis_new_adj (hdr->source_id," ", 0, circuit); + if (adj == NULL) + return ISIS_ERROR; + 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); + + /* + * Lets get the TLVS now + */ + expected |= TLVFLAG_AREA_ADDRS; + expected |= TLVFLAG_AUTH_INFO; + expected |= TLVFLAG_NLPID; + expected |= TLVFLAG_IPV4_ADDR; + expected |= TLVFLAG_IPV6_ADDR; + + retval = parse_tlvs (circuit->area->area_tag, + STREAM_PNT (circuit->rcv_stream), + ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN + - ISIS_FIXED_HDR_LEN, + &expected, + &found, + &tlvs); + + if (retval > ISIS_WARNING) { + free_tlvs (&tlvs); + return retval; + }; + + /* 8.2.5.1 c) Authentication */ + if (circuit->passwd.type) { + if (!(found & TLVFLAG_AUTH_INFO) || + authentication_check (&circuit->passwd, &tlvs.auth_info)) { + isis_event_auth_failure (circuit->area->area_tag, + "P2P hello authentication failure", + hdr->source_id); + return ISIS_OK; + } + } + + /* we do this now because the adj may not survive till the end... */ + + /* we need to copy addresses to the adj */ + tlvs_to_adj_ipv4_addrs (&tlvs,adj); + +#ifdef HAVE_IPV6 + tlvs_to_adj_ipv6_addrs (&tlvs,adj); +#endif /* HAVE_IPV6 */ + + /* lets take care of the expiry */ + if(adj->t_expire) { + thread_cancel (adj->t_expire); + } + adj->t_expire = thread_add_timer (master, 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"); + 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"); + 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 (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"); + 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; + } + } + } + /* 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; + adj->level = hdr->circuit_t; + + 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; + struct tlvs tlvs; + u_char *snpa; + struct listnode *node; + + 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_info ("level %d LAN Hello received over circuit with " + "externalDomain = true", level); + return ISIS_WARNING; + } + + if (!accept_level (level, circuit->circuit_is_type)) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_info ("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_info ("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.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 && + hdr.circuit_t != IS_LEVEL_1_AND_2 ) { + zlog_warn ("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; + + 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); + + 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 (circuit->passwd.type) { + if (!(found & TLVFLAG_AUTH_INFO) || + authentication_check (&circuit->passwd, &tlvs.auth_info)) { + isis_event_auth_failure (circuit->area->area_tag, + "LAN hello authentication failure", + hdr.source_id); + retval = ISIS_WARNING; + goto out; + } + } + + /* + * Accept the level 1 adjacency only if a match between local and + * remote area addresses is found + */ + if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs)) { + if (isis->debugs & DEBUG_ADJ_PACKETS) { + zlog_info ("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_info ("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) || !ip_match(circuit->ip_addrs, tlvs.ipv4_addrs)) { + zlog_info("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) { + /* + * 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; + + adj->level = level; + isis_adj_state_change(adj, ISIS_ADJ_INITIALIZING, NULL); + + if (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]); + } + + 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; + } + +#if 0 + /* Old solution: believe the lan-header always + */ + if (level == 1) { + memcpy(circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); + } else if (level == 2) { + memcpy(circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); + } +#endif + + 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); + + /* which protocol are spoken ??? */ + if (found & TLVFLAG_NLPID) + tlvs_to_adj_nlpids (&tlvs, adj); + + /* 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 */ + if (adj->t_expire) { + thread_cancel (adj->t_expire); + } + adj->t_expire = thread_add_timer (master, 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) { + LIST_LOOP (tlvs.lan_neighs, snpa, node) + if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) { + isis_adj_state_change (adj, ISIS_ADJ_UP, + "own SNPA found in LAN Neighbours TLV"); + } + } + } + + out: + /* DEBUG_ADJ_PACKETS */ + if (isis->debugs & DEBUG_ADJ_PACKETS) { + /* FIXME: is this place right? fix missing info */ + zlog_info ("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->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; + + /* Sanity check - FIXME: move to correct place */ + 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); + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_info ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " + "lifetime %us, len %lu, on %s", + circuit->area->area_tag, + level, + rawlspid_print(hdr->lsp_id), + ntohl(hdr->seq_num), + ntohs(hdr->checksum), + ntohs(hdr->rem_lifetime), + circuit->rcv_stream->endp, + circuit->interface->name); + } + + assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN); + + /* Checksum sanity check - FIXME: move to correct place */ + /* 12 = sysid+pdu+remtime */ + if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4, + ntohs (hdr->pdu_len) - 12, &hdr->checksum)) { + zlog_info ("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_info ("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->circuit_is_type)) { + zlog_info ("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->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 == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) : + (passwd = &circuit->area->domain_passwd); + if (passwd->type) { + if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area, + ntohs (hdr->pdu_len), 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 */ + /* FIXME : Point To Point */ + + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]); + if (!adj) { + zlog_info ("(%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 == 1) && + (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) || + ((level == 2) && + (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1))) + return ISIS_WARNING; /* Silently discard */ + } + } + 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, hdr, circuit->rcv_stream, circuit->area); + /* ii */ + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + /* 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 { + /* our own LSP -> 7.3.16.4 c) */ + if (LSP_PSEUDO_ID(lsp->lsp_header->lsp_id) != circuit->circuit_id || + (LSP_PSEUDO_ID(lsp->lsp_header->lsp_id) == circuit->circuit_id && + circuit->u.bc.is_dr[level - 1] == 1) ) { + lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1); + zlog_info ("LSP LEN: %d", ntohs (lsp->lsp_header->pdu_len)); + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs (lsp->lsp_header->pdu_len) - 12, 12); + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + zlog_info ("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)); + lsp->lsp_header->rem_lifetime = htons (isis_jitter + (circuit->area-> + max_lsp_lifetime[level-1], + MAX_AGE_JITTER)); + + } else { + /* Got purge for own pseudo-lsp, and we are not DR */ + lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level); + } + } + } + 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, ... */ + + else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { + /* 7.3.16.1 */ + lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1); + + iso_csum_create (STREAM_DATA (lsp->pdu) + 12, + ntohs(lsp->lsp_header->pdu_len) - 12, 12); + + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + zlog_info ("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)); + lsp->lsp_header->rem_lifetime = htons (isis_jitter + (circuit-> + area->max_lsp_lifetime[level-1], + MAX_AGE_JITTER)); + + } + } 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)){ + /* i */ + if (lsp) { +#ifdef EXTREME_DEBUG + zlog_info ("level %d number is - %ld", level, + circuit->area->lspdb[level-1]->dict_nodecount); +#endif /* EXTREME DEBUG */ + lsp_search_and_destroy (hdr->lsp_id, circuit->area->lspdb[level-1]); + /* exists, so we overwrite */ +#ifdef EXTREME_DEBUG + zlog_info ("level %d number is - %ld",level, + circuit->area->lspdb[level-1]->dict_nodecount); +#endif /* EXTREME DEBUG */ + } + /* + * 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_info ("Got lsp frag, while zero lsp not database"); + return ISIS_OK; + } + } + lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, ntohs (hdr->pdu_len), + lsp0, circuit->area); + lsp->level = level; + lsp->adj = adj; + lsp_insert (lsp, circuit->area->lspdb[level-1]); + /* ii */ + ISIS_FLAGS_SET_ALL (lsp->SRMflags); + /* 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, hdr, circuit->rcv_stream, circuit->area); + 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); + } + } + if (lsp) + lsp->adj = adj; + return retval; +} + +/* + * Process Sequence Numbers + * ISO - 10589 + * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU + */ + +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 = ' '; + int 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; + struct isis_lsp *lsp; + struct lsp_entry *entry; + struct listnode *node,*node2; + 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); + circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN; + len = ntohs(chdr->pdu_len); + if (len < ISIS_CSNP_HDRLEN) { + zlog_warn ("Received a CSNP with bogus length!"); + return ISIS_OK; + } + } else { + typechar = 'P'; + phdr = (struct isis_partial_seqnum_hdr*)STREAM_PNT(circuit->rcv_stream); + circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN; + len = ntohs(phdr->pdu_len); + if (len < ISIS_PSNP_HDRLEN) { + zlog_warn ("Received a CSNP with bogus length!"); + return ISIS_OK; + } + } + + /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ + if (circuit->ext_domain) { + + zlog_info ("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->circuit_is_type)) { + + zlog_info ("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->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)) { + if (!circuit->u.bc.is_dr[level-1]) { + + zlog_info ("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) + 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; + retval = parse_tlvs (circuit->area->area_tag, + STREAM_PNT(circuit->rcv_stream), + len - circuit->rcv_stream->getp, + &expected, + &found, + &tlvs); + + if (retval > ISIS_WARNING) { + zlog_warn ("something went very wrong processing SNP"); + free_tlvs (&tlvs); + return retval; + } + + (level == 1) ? (passwd = &circuit->area->area_passwd) : + (passwd = &circuit->area->domain_passwd); + if (passwd->type) { + if (!(found & TLVFLAG_AUTH_INFO) || + authentication_check (passwd, &tlvs.auth_info)) { + isis_event_auth_failure (circuit->area->area_tag, "SNP authentication" + " failure", phdr ? + phdr->source_id : chdr->source_id); + return ISIS_OK; + } + } + + /* debug isis snp-packets */ + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_info ("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) { + LIST_LOOP (tlvs.lsp_entries,entry,node) { + zlog_info("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) { + LIST_LOOP (tlvs.lsp_entries, entry, node) { + 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); + } else { + /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p*/ + 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_insert (lsp, circuit->area->lspdb[level - 1]); + 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_ 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) { + LIST_LOOP (tlvs.lsp_entries, entry, node) { + LIST_LOOP (lsp_list, lsp, node2) { + 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) */ + LIST_LOOP (lsp_list, lsp, node2) { + ISIS_SET_FLAG (lsp->SRMflags, circuit); + } + /* lets free it */ + list_free (lsp_list); + } + + free_tlvs (&tlvs); + return retval; +} + +int +process_csnp (int level, struct isis_circuit *circuit, u_char *ssnpa) +{ + + /* 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); +} + +int +process_psnp (int level, struct isis_circuit *circuit, u_char *ssnpa) +{ + + if ((stream_get_endp (circuit->rcv_stream) - + stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) { + zlog_warn ("Packet too short"); + 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 + */ +int +process_is_hello (struct isis_circuit *circuit) +{ + struct isis_adjacency *adj; + int retval = ISIS_OK; + u_char neigh_len; + u_char *sysid; + + /* 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, " ", 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, " ", 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 + */ + +int +isis_handle_pdu (struct isis_circuit *circuit, u_char *ssnpa) +{ + + struct isis_fixed_hdr *hdr; + struct esis_fixed_hdr *esis_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_warn ("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){ + esis_hdr = (struct esis_fixed_hdr*)STREAM_DATA(circuit->rcv_stream); + stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN); + /* FIXME: Need to do some acceptence tests */ + /* example length... */ + switch (esis_hdr->pdu_type) { + case ESH_PDU: + /* FIXME */ + break; + case ISH_PDU: + zlog_info ("AN ISH PDU!!"); + retval = process_is_hello (circuit); + break; + default: + return ISIS_ERROR; + } + return retval; + } else { + 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; + } + /* 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. + */ + circuit->t_read = thread_add_read (master, 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. + */ + 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 + */ +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; + + u_int32_t interval; + unsigned long len_pointer, length; + int retval; + + 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 == 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->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_putp (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->u.bc.priority[level - 1]; + if(level == 1 && circuit->u.bc.l1_desig_is) { + memcpy(hello_hdr.lan_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); + } else if (level == 2 && circuit->u.bc.l2_desig_is){ + 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 */ + if (circuit->passwd.type) + if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, + circuit->passwd.passwd, circuit->snd_stream)) + return ISIS_WARNING; + /* Area Addresses TLV */ + assert (circuit->area); + if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) + 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 == 1 && circuit->u.bc.lan_neighs[0]->count > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], + circuit->snd_stream)) + return ISIS_WARNING; + if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 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 && circuit->ip_addrs->count > 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 && + circuit->ipv6_link->count > 0) + if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream)) + return ISIS_WARNING; +#endif /* HAVE_IPV6 */ + + if (circuit->u.bc.pad_hellos) + if (tlv_add_padding (circuit->snd_stream)) + return ISIS_WARNING; + + length = stream_get_putp (circuit->snd_stream); + /* Update PDU length */ + stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t)length); + + retval = circuit->tx (circuit, level); + if (retval) + zlog_warn ("sending of LAN Level %d Hello failed", level); + + /* DEBUG_ADJ_PACKETS */ + if (isis->debugs & DEBUG_ADJ_PACKETS) { + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + zlog_info ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld", + circuit->area->area_tag, level, circuit->interface->name, + STREAM_SIZE(circuit->snd_stream)); + } else { + zlog_info ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld", + circuit->area->area_tag, circuit->interface->name, + STREAM_SIZE(circuit->snd_stream)); + } + } + + + return retval; +} + +int +send_lan_hello (struct isis_circuit *circuit, int level) +{ + return send_hello (circuit,level); +} + +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_lan_hello (circuit, 1); + + /* set next timer thread */ + circuit->u.bc.t_send_lan_hello[0] = + thread_add_timer (master, 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_lan_hello (circuit, 2); + + /* set next timer thread*/ + circuit->u.bc.t_send_lan_hello[1] = + thread_add_timer (master, 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*/ + circuit->u.p2p.t_send_p2p_hello = thread_add_timer + (master, send_p2p_hello, circuit, isis_jitter (circuit->hello_interval[1], + IIH_JITTER)); + + return ISIS_OK; +} + +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; + int retval = ISIS_OK; + unsigned long lenp; + u_int16_t length; + + if (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_putp (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 == 1) + passwd = &circuit->area->area_passwd; + else + passwd = &circuit->area->domain_passwd; + + if (passwd->type) + retval = tlv_add_authinfo (passwd->type, passwd->len, + passwd->passwd, circuit->snd_stream); + + if (!retval && lsps) { + retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); + } + length = (u_int16_t)stream_get_putp (circuit->snd_stream); + assert (length >= ISIS_CSNP_HDRLEN); + /* Update PU length */ + stream_putw_at (circuit->snd_stream, lenp, length); + + return retval; +} + +/* + * FIXME: support multiple CSNPs + */ + +int +send_csnp (struct isis_circuit *circuit, int level) +{ + int retval = ISIS_OK; + 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; + + memset (start,0x00, ISIS_SYS_ID_LEN + 2); + memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); + + if (circuit->area->lspdb[level-1] && + dict_count (circuit->area->lspdb[level-1]) > 0) { + list = list_new (); + lsp_build_list (start, stop, list, circuit->area->lspdb[level-1]); + + if (circuit->snd_stream == NULL) + circuit->snd_stream = stream_new (ISO_MTU(circuit)); + else + stream_reset (circuit->snd_stream); + + retval = build_csnp (level, start, stop, list, circuit); + + if (isis->debugs & DEBUG_SNP_PACKETS) { + zlog_info ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", + circuit->area->area_tag, level, circuit->interface->name, + STREAM_SIZE(circuit->snd_stream)); + LIST_LOOP (list, lsp, node) { + zlog_info("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)); + } + } + + list_delete (list); + + if (retval == ISIS_OK) + retval = circuit->tx (circuit, level); + } + 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 */ + circuit->t_send_csnp[0] = thread_add_timer (master, + 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 */ + circuit->t_send_csnp[1] = thread_add_timer (master, + send_l2_csnp, + circuit, + isis_jitter + (circuit->csnp_interval[1], + CSNP_JITTER)); + return retval; +} + +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; + int retval = 0; + struct isis_lsp *lsp; + struct isis_passwd *passwd; + struct listnode *node; + + if (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_putp (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 == 1) + passwd = &circuit->area->area_passwd; + else + passwd = &circuit->area->domain_passwd; + + if (passwd->type) + retval = tlv_add_authinfo (passwd->type, passwd->len, + passwd->passwd, circuit->snd_stream); + + if (!retval && lsps) { + retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); + } + + if (isis->debugs & DEBUG_SNP_PACKETS) { + LIST_LOOP (lsps, lsp, node) { + zlog_info("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_putp (circuit->snd_stream); + assert (length >= ISIS_PSNP_HDRLEN); + /* Update PDU length */ + stream_putw_at (circuit->snd_stream, lenp, length); + + return ISIS_OK; +} + +/* + * 7.3.15.4 action on expiration of partial SNP interval + * level 1 + */ +int +send_psnp (int level, struct isis_circuit *circuit) +{ + int retval = ISIS_OK; + struct isis_lsp *lsp; + struct list *list = NULL; + struct listnode *node; + + if ((circuit->circ_type == CIRCUIT_T_BROADCAST && + !circuit->u.bc.is_dr[level - 1]) || + circuit->circ_type != CIRCUIT_T_BROADCAST) { + + if (circuit->area->lspdb[level-1] && + dict_count (circuit->area->lspdb[level-1]) > 0) { + list = list_new (); + lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level-1]); + + if (listcount(list) > 0) { + if (circuit->snd_stream == NULL) + circuit->snd_stream = stream_new (ISO_MTU(circuit)); + else + stream_reset (circuit->snd_stream); + + + if (isis->debugs & DEBUG_SNP_PACKETS) + zlog_info ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld", + circuit->area->area_tag, level, circuit->interface->name, + STREAM_SIZE(circuit->snd_stream)); + + retval = build_psnp (level, circuit, list); + if (retval == ISIS_OK) + retval = circuit->tx (circuit, level); + + if (retval == ISIS_OK) { + /* + * sending succeeded, we can clear SSN flags of this circuit + * for the LSPs in list + */ + for (node = listhead (list); node; nextnode(node)) { + lsp = getdata (node); + 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 */ + circuit->t_send_psnp[0] = thread_add_timer (master, + 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 */ + circuit->t_send_psnp[1] = thread_add_timer (master, + send_l2_psnp, + circuit, + isis_jitter + (circuit->psnp_interval[1], + PSNP_JITTER)); + + return retval; +} + + +void +build_link_state (struct isis_lsp *lsp, struct isis_circuit *circuit, + struct stream *stream) +{ + unsigned long length; + + stream_put (stream, lsp->pdu, ntohs(lsp->lsp_header->pdu_len)); + length = stream_get_putp (stream); + + return; +} + + +/* + * 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 = 0; + + circuit = THREAD_ARG (thread); + assert (circuit); + + if (circuit->state == C_STATE_UP) { + node = listhead (circuit->lsp_queue); + assert (node); + + lsp = getdata (node); + + /* + * Do not send if levels do not match + */ + if (!(lsp->level & circuit->circuit_is_type)) + goto dontsend; + + /* + * Do not send if we do not have adjacencies in state up on the circuit + */ + if (circuit->upadjcount[lsp->level - 1] == 0) + goto dontsend; + /* only send if it needs sending */ + if ((time(NULL) - lsp->last_sent) >= + circuit->area->lsp_gen_interval[lsp->level-1]) { + + if (isis->debugs & DEBUG_UPDATE_PACKETS) { + zlog_info ("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); + } + /* copy our lsp to the send buffer */ + circuit->snd_stream->getp = lsp->pdu->getp; + circuit->snd_stream->putp = lsp->pdu->putp; + circuit->snd_stream->endp = lsp->pdu->endp; + memcpy (circuit->snd_stream->data, lsp->pdu->data, lsp->pdu->endp); + + retval = circuit->tx (circuit, lsp->level); + + /* + * If the sending succeeded, we can del the lsp from circuits lsp_queue + */ + if (retval == ISIS_OK) { + list_delete_node (circuit->lsp_queue, node); + + /* + * On broadcast circuits also the SRMflag can be cleared + */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + + if (flags_any_set (lsp->SRMflags) == 0) { + /* + * need to remember when we were last sent + */ + lsp->last_sent = time (NULL); + } + } else { + zlog_info ("sending of level %d link state failed", lsp->level); + } + } else { + /* my belief is that if it wasn't his time, the lsp can be removed + * from the queue + */ + dontsend: + list_delete_node (circuit->lsp_queue, node); + } +#if 0 + /* + * If there are still LSPs send next one after lsp-interval (33 msecs) + */ + if (listcount (circuit->lsp_queue) > 0) + thread_add_timer (master, send_lsp, circuit, + 1); +#endif + } + + 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 == 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_putp (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_putp (circuit->snd_stream); + /* Update PDU length */ + stream_putw_at (circuit->snd_stream, lenp, length); + + retval = circuit->tx (circuit, level); + + return retval; +} + +#if 0 +/* + * ISH PDU Processing + */ + + + /* + * Let's first check if the local and remote system have any common area + * addresses + */ + if (area_match(tlvs.area_addrs, isis->man_area_addrs) == 0) { + if (circuit->circuit_t == IS_LEVEL_2) { + /* do as in table 8 (p. 40) */ + switch (circuit_type) { + case IS_LEVEL_1: + if (adj->adj_state != ISIS_ADJ_UP) { + /* Reject */ + zlog_warn("areaMismatch"); + retval = ISIS_WARNING; + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch", + circuit->adjdb); + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2 || + adj->adj_usage == ISIS_ADJ_LEVEL2) { + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System", + circuit->adjdb); + } + break; + case IS_LEVEL_2: + if (adj->adj_state != ISIS_ADJ_UP) { + isis_adj_state_change (adj, ISIS_ADJ_UP, NULL, circuit->adjdb); + adj->adj_usage = ISIS_ADJ_LEVEL2; + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1 || + adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System", + circuit->adjdb); + } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { + ; /* Accept */ + } + break; + case IS_LEVEL_1_AND_2: + if (adj->adj_state != ISIS_ADJ_UP) { + isis_adj_state_change (adj, ISIS_ADJ_UP, NULL, circuit->adjdb); + adj->adj_usage = ISIS_ADJ_LEVEL2; + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System", + circuit->adjdb); + } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { + isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch", + circuit->adjdb); + } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { + ; /* Accept */ + } + break; + } + goto mismatch; + } else { + isis_delete_adj (adj, circuit->adjdb); + zlog_warn("areaMismatch"); + return ISIS_WARNING; + } + } + +mismatch: +#endif + + + + diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h new file mode 100644 index 00000000..99403680 --- /dev/null +++ b/isisd/isis_pdu.h @@ -0,0 +1,257 @@ +/* + * 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 + +/* + * 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; +}; + +#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 Lenght | 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 Lenght + 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 + +#define L1_COMPLETE_SEQ_NUM 24 +#define L2_COMPLETE_SEQ_NUM 25 +/* + * L1 and L2 IS to IS complete sequence numbers PDU header + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * + PDU Lenght + 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 + +/* + * 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 + +/* + * 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); + + +int authentication_check (struct isis_passwd *one, + struct isis_passwd *theother); + +#endif /* _ZEBRA_ISIS_PDU_H */ + + + + + diff --git a/isisd/isis_route.c b/isisd/isis_route.c new file mode 100644 index 00000000..74231adc --- /dev/null +++ b/isisd/isis_route.c @@ -0,0 +1,615 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <zebra.h> +#include <net/ethernet.h> + +#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 "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; +extern struct thread_master *master; + +struct isis_nexthop * +isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) + +{ + struct listnode *node; + struct isis_nexthop *nexthop; + + for (node = listhead (isis->nexthops); node; nextnode (node)) { + nexthop = getdata (node); + if (nexthop->ifindex != ifindex) + continue; + if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0) + continue; + + nexthop->lock++; + return nexthop; + } + + nexthop = XMALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop)); + if (!nexthop) { + zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!"); + } + + memset (nexthop, 0, sizeof (struct isis_nexthop)); + nexthop->ifindex = ifindex; + memcpy (&nexthop->ip, ip, sizeof (struct in_addr)); + listnode_add (isis->nexthops, nexthop); + nexthop->lock++; + + return nexthop; +} + + +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; +} + +int +nexthoplookup (struct list *nexthops, struct in_addr *ip, + unsigned int ifindex) +{ + struct listnode *node; + struct isis_nexthop *nh; + + for (node = listhead (nexthops); node; nextnode (node)) { + nh = getdata (node); + if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) && + ifindex == nh->ifindex) + return 1; + } + + return 0; +} + +void +nexthop_print (struct isis_nexthop *nh) +{ + u_char buf[BUFSIZ]; + + inet_ntop (AF_INET, &nh->ip, buf, BUFSIZ); + + zlog_info (" %s %u", buf, nh->ifindex); +} + +void +nexthops_print (struct list *nhs) +{ + struct listnode *node; + + for (node = listhead(nhs); node; nextnode (node)) + nexthop_print (getdata (node)); +} + +#ifdef HAVE_IPV6 + +struct isis_nexthop6 * +isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) +{ + + struct isis_nexthop6 *nexthop6; + + nexthop6 = XMALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6)); + if (!nexthop6) { + zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!"); + } + + memset (nexthop6, 0, sizeof (struct isis_nexthop6)); + nexthop6->ifindex = ifindex; + memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr)); + nexthop6->lock++; + + return nexthop6; +} + +struct isis_nexthop6 * +isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex) + +{ + struct listnode *node; + struct isis_nexthop6 *nexthop6; + + for (node = listhead (isis->nexthops6); node; nextnode (node)) { + nexthop6 = getdata (node); + 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; +} + + +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; +} + +int +nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6, + unsigned int ifindex) +{ + struct listnode *node; + struct isis_nexthop6 *nh6; + + for (node = listhead (nexthops6); node; nextnode (node)) { + nh6 = getdata (node); + if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) && + ifindex == nh6->ifindex) + return 1; + } + + return 0; +} + +void +nexthop6_print (struct isis_nexthop6 *nh6) +{ + u_char buf[BUFSIZ]; + + inet_ntop (AF_INET6, &nh6->ip6, buf, BUFSIZ); + + zlog_info (" %s %u", buf, nh6->ifindex); +} + +void +nexthops6_print (struct list *nhs6) +{ + struct listnode *node; + + for (node = listhead(nhs6); node; nextnode (node)) + nexthop6_print (getdata (node)); +} + + +#endif /* HAVE_IPV6 */ + +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 (node = listhead (adj->ipv4_addrs); node; nextnode (node)) { + ipv4_addr = getdata (node); + if (!nexthoplookup (nexthops, ipv4_addr, + adj->circuit->interface->ifindex)) { + nh = isis_nexthop_create (ipv4_addr, + adj->circuit->interface->ifindex); + listnode_add (nexthops, nh); + } + } +} + +#ifdef HAVE_IPV6 +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 (node = listhead (adj->ipv6_addrs); node; nextnode (node)) { + ipv6_addr = getdata (node); + if (!nexthop6lookup (nexthops6, ipv6_addr, + adj->circuit->interface->ifindex)) { + nh6 = isis_nexthop6_create (ipv6_addr, + adj->circuit->interface->ifindex); + listnode_add (nexthops6, nh6); + } + } +} +#endif /* HAVE_IPV6 */ + +struct isis_route_info * +isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, + struct list *adjacencies) +{ + struct isis_route_info *rinfo; + struct isis_adjacency *adj; + struct listnode *node; + + rinfo = XMALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info)); + if (!rinfo) { + zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!"); + return NULL; + } + memset (rinfo, 0, sizeof (struct isis_route_info)); + + if (family == AF_INET) { + rinfo->nexthops = list_new (); + for (node = listhead (adjacencies); node; nextnode (node)) { + adj = getdata (node); + adjinfo2nexthop (rinfo->nexthops, adj); + } + } +#ifdef HAVE_IPV6 + if (family == AF_INET6) { + rinfo->nexthops6 = list_new (); + for (node = listhead (adjacencies); node; nextnode (node)) { + adj =getdata (node); + adjinfo2nexthop6 (rinfo->nexthops6, adj); + } + } + +#endif /* HAVE_IPV6 */ + + rinfo->cost = cost; + rinfo->depth = depth; + + return rinfo; +} + + +void +isis_route_info_delete (struct isis_route_info *route_info) +{ + + if (route_info->nexthops) { + route_info->nexthops->del = (void *)isis_nexthop_delete; + list_delete (route_info->nexthops); + } + +#ifdef HAVE_IPV6 + if (route_info->nexthops6) { + route_info->nexthops6->del = (void *)isis_nexthop6_delete; + list_delete (route_info->nexthops6); + } +#endif /* HAVE_IPV6 */ + + XFREE (MTYPE_ISIS_ROUTE_INFO, route_info); +} + +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; +} + +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 (!isis_route_info_same_attrib (new, old)) + return 0; + + if (family == AF_INET) { + for (node = listhead (new->nexthops); node; nextnode (node)) { + nexthop = (struct isis_nexthop *) getdata (node); + if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) == 0) + return 0; + } + + for (node = listhead (old->nexthops); node; nextnode (node)) { + nexthop = (struct isis_nexthop *) getdata (node); + if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) == 0) + return 0; + } + } +#ifdef HAVE_IPV6 + else if (family == AF_INET6) { + for (node = listhead (new->nexthops6); node; nextnode (node)) { + nexthop6 = (struct isis_nexthop6 *) getdata (node); + if (nexthop6lookup (old->nexthops6, &nexthop6->ip6, + nexthop6->ifindex) == 0) + return 0; + } + + for (node = listhead (old->nexthops6); node; nextnode (node)) { + nexthop6 = (struct isis_nexthop6 *) getdata (node); + if (nexthop6lookup (new->nexthops6, &nexthop6->ip6, + nexthop6->ifindex) == 0) + return 0; + } + } +#endif /* HAVE_IPV6 */ + + return 1; +} + + +void +isis_nexthops_merge (struct list *new, struct list *old) +{ + struct listnode *node; + struct isis_nexthop *nexthop; + + for (node = listhead (new); node; nextnode (node)) { + nexthop = (struct isis_nexthop *) getdata (node); + if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex)) + continue; + listnode_add (old, nexthop); + nexthop->lock++; + } +} + + +#ifdef HAVE_IPV6 +void +isis_nexthops6_merge (struct list *new, struct list *old) +{ + struct listnode *node; + struct isis_nexthop6 *nexthop6; + + for (node = listhead (new); node; nextnode (node)) { + nexthop6 = (struct isis_nexthop6 *) getdata (node); + if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex)) + continue; + listnode_add (old, nexthop6); + nexthop6->lock++; + } +} +#endif /* HAVE_IPV6 */ + +void +isis_route_info_merge (struct isis_route_info *new, + struct isis_route_info *old, u_char family) +{ + + if (family == AF_INET) + isis_nexthops_merge (new->nexthops, old->nexthops); +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + isis_nexthops6_merge (new->nexthops6, old->nexthops6); +#endif /* HAVE_IPV6 */ + + return; +} + + +int +isis_route_info_prefer_new (struct isis_route_info *new, + struct isis_route_info *old) +{ + + if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE)) + return 1; + + if (new->cost < old->cost) + return 1; + + return 0; +} + + +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) +{ + 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, buff, BUFSIZ); + + rinfo_new = isis_route_info_new (cost, depth, family, 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, prefix); +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + route_node = route_node_get (area->route_table6, prefix); +#endif /* HAVE_IPV6 */ + else + return NULL; + rinfo_old = route_node->info; + if (!rinfo_old) { + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_info ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); + SET_FLAG(rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE); + route_node->info = rinfo_new; + return rinfo_new; + } + + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_info ("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_info ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff); + isis_route_info_delete (rinfo_new); + route_info = rinfo_old; + } else if (isis_route_info_same_attrib (rinfo_new, rinfo_old)) { + /* merge the nexthop lists */ + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_info ("ISIS-Rte (%s) route changed (same attribs): %s", + area->area_tag, buff); +#ifdef EXTREME_DEBUG + zlog_info ("Old nexthops"); + nexthops6_print (rinfo_old->nexthops6); + zlog_info ("New nexthops"); + nexthops6_print (rinfo_new->nexthops6); +#endif /* EXTREME_DEBUG */ + isis_route_info_merge (rinfo_new, rinfo_old, family); + isis_route_info_delete (rinfo_new); + route_info = rinfo_old; + } else { + if (isis_route_info_prefer_new (rinfo_new, rinfo_old)) { + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_info ("ISIS-Rte (%s) route changed: %s", area->area_tag, buff); + isis_route_info_delete (rinfo_old); + route_info = rinfo_new; + } else { + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_info ("ISIS-Rte (%s) route rejected: %s", area->area_tag, buff); + isis_route_info_delete (rinfo_new); + route_info = rinfo_old; + } + } + + SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE); + route_node->info = route_info; + + return route_info; +} + +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_info ("ISIS-Rte: tried to delete non-existant route %s", buff); + return; + } + + if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC)) { + UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); + if (isis->debugs & DEBUG_RTE_EVENTS) + zlog_info ("ISIS-Rte: route delete %s", buff); + isis_zebra_route_update (prefix, rinfo); + } + isis_route_info_delete (rinfo); + rode->info = NULL; + + return; +} + +int +isis_route_validate (struct thread *thread) +{ + struct isis_area *area; + struct route_table *table; + struct route_node *rode; + struct isis_route_info *rinfo; + u_char buff[BUFSIZ]; +#ifdef HAVE_IPV6 + int v6done = 0; +#endif + area = THREAD_ARG (thread); + table = area->route_table; +#ifdef HAVE_IPV6 + again: +#endif + for (rode = route_top (table); rode; rode = route_next (rode)) { + if (rode->info == NULL) + continue; + rinfo = rode->info; + + if (isis->debugs & DEBUG_RTE_EVENTS) { + prefix2str (&rode->p, buff, BUFSIZ); + zlog_info ("ISIS-Rte (%s): route validate: %s %s %s", + area->area_tag, + (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ? + "sync'ed": "nosync"), + (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ? + "active": "inactive"), buff); + } + + isis_zebra_route_update (&rode->p, rinfo); + if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) + isis_route_delete (&rode->p, area->route_table); + } +#ifdef HAVE_IPV6 + if (v6done) + return ISIS_OK; + table = area->route_table6; + v6done = 1; + goto again; +#endif + + return ISIS_OK; +} diff --git a/isisd/isis_route.h b/isisd/isis_route.h new file mode 100644 index 00000000..7137948e --- /dev/null +++ b/isisd/isis_route.h @@ -0,0 +1,61 @@ +/* + * 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; + unsigned int lock; +}; +#endif /* HAVE_IPV6 */ + +struct isis_nexthop { + unsigned int ifindex; + struct in_addr ip; + unsigned int lock; +}; + +struct isis_route_info { +#define ISIS_ROUTE_FLAG_ZEBRA_SYNC 0x01 +#define ISIS_ROUTE_FLAG_ACTIVE 0x02 + 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 isis_route_validate (struct thread *thread); + +#endif /* _ZEBRA_ISIS_ROUTE_H */ diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c new file mode 100644 index 00000000..4df983d2 --- /dev/null +++ b/isisd/isis_routemap.c @@ -0,0 +1,100 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <zebra.h> +#include <net/ethernet.h> + +#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 "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; + +void +isis_route_map_upd() +{ + int i = 0; + + if (!isis) + return; + + for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { + if (isis->rmap[i].name) + isis->rmap[i].map = 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, 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); + +} diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c new file mode 100644 index 00000000..d6949817 --- /dev/null +++ b/isisd/isis_spf.c @@ -0,0 +1,1293 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <zebra.h> +#include <net/ethernet.h> + +#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 "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" + +extern struct isis *isis; +extern struct thread_master *master; +extern struct host host; + +int isis_run_spf_l1 (struct thread *thread); +int isis_run_spf_l2 (struct thread *thread); + +/* performace issue ???? */ +void +union_adjlist( struct list *target, struct list *source ) +{ + struct isis_adjacency *adj, *adj2; + struct listnode *node, *node2; + + zlog_info ("Union adjlist!"); + for (node = listhead (source); node; nextnode (node)) { + adj = getdata (node); + + /* lookup adjacency in the source list */ + for (node2 = listhead (target); node2; nextnode (node2)) { + adj2 = getdata(node2); + if (adj == adj2) break; + } + + if (!node2) listnode_add (target, adj); + } +} + + +/* 7.2.7 */ +void +remove_excess_adjs (struct list *adjs) +{ + struct listnode *node, *excess = NULL; + struct isis_adjacency *adj, *candidate = NULL; + int comp; + + for (node = listhead (adjs); node; nextnode (node)) { + if (excess == NULL) + excess = node; + candidate = getdata (excess); + adj = getdata (node); + 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; +} + +const char * +vtype2string (enum vertextype vtype) +{ + switch (vtype) { + case VTYPE_PSEUDO_IS: + return "pseudo_IS"; + break; + case VTYPE_NONPSEUDO_IS: + return "IS"; + break; + case VTYPE_ES: + return "ES"; + break; + case VTYPE_IPREACH_INTERNAL: + return "IP internal"; + break; + case VTYPE_IPREACH_EXTERNAL: + return "IP external"; + 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 */ +} + +char * +vid2string (struct isis_vertex *vertex, u_char *buff) +{ + switch (vertex->type) { + case VTYPE_PSEUDO_IS: + return rawlspid_print (vertex->N.id); + break; + case VTYPE_NONPSEUDO_IS: + case VTYPE_ES: + return sysid_print (vertex->N.id); + break; + case VTYPE_IPREACH_INTERNAL: + case VTYPE_IPREACH_EXTERNAL: +#ifdef HAVE_IPV6 + case VTYPE_IP6REACH_INTERNAL: + case VTYPE_IP6REACH_EXTERNAL: +#endif /* HAVE_IPV6 */ + prefix2str ((struct prefix *)&vertex->N.prefix, buff, BUFSIZ); + break; + default: + return "UNKNOWN"; + } + + return buff; +} + +struct isis_spftree * +isis_spftree_new () +{ + struct isis_spftree *tree; + + tree = XMALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree)); + if (tree == NULL) { + zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!"); + return NULL; + } + memset (tree, 0, sizeof (struct isis_spftree)); + + tree->tents = list_new (); + tree->paths = list_new (); + return tree; +} + +void +isis_vertex_del (struct isis_vertex *vertex) +{ + + list_delete (vertex->Adj_N); + + XFREE (MTYPE_ISIS_VERTEX, vertex); + + return; +} + +void +isis_spftree_del (struct isis_spftree *spftree) +{ + + spftree->tents->del = (void *)isis_vertex_del; + list_delete (spftree->tents); + + spftree->paths->del = (void *)isis_vertex_del; + list_delete (spftree->paths); + + XFREE (MTYPE_ISIS_SPFTREE, spftree); + + return; +} + +void +spftree_area_init (struct isis_area *area) +{ + + if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL) { + area->spftree[0] = isis_spftree_new (); +#ifdef HAVE_IPV6 + area->spftree6[0] = isis_spftree_new (); +#endif + + /* thread_add_timer (master, isis_run_spf_l1, area, + isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */ + } + + if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL) { + area->spftree[1] = isis_spftree_new (); +#ifdef HAVE_IPV6 + area->spftree6[1] = isis_spftree_new (); +#endif + /* thread_add_timer (master, isis_run_spf_l2, area, + isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */ + } + + return; +} + +struct isis_vertex * +isis_vertex_new (void *id, enum vertextype vtype) +{ + struct isis_vertex *vertex; + + vertex = XMALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); + if (vertex == NULL) { + zlog_err ("isis_vertex_new Out of memory!"); + return NULL; + } + + memset (vertex, 0, sizeof (struct isis_vertex)); + vertex->type = vtype; + switch (vtype) { + case VTYPE_ES: + case VTYPE_NONPSEUDO_IS: + memcpy (vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN); + break; + case VTYPE_PSEUDO_IS: + memcpy (vertex->N.id, (u_char *)id, ISIS_SYS_ID_LEN + 1); + break; + case VTYPE_IPREACH_INTERNAL: + case VTYPE_IPREACH_EXTERNAL: +#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 (); + + return vertex; +} + +/* + * Add this IS to the root of SPT + */ +void +isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area, + int level) +{ + struct isis_vertex *vertex; + struct isis_lsp *lsp; + u_char lspid[ISIS_SYS_ID_LEN + 2]; +#ifdef EXTREME_DEBUG + u_char buff[BUFSIZ]; +#endif /* EXTREME_DEBUG */ + memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(lspid) = 0; + LSP_FRAGMENT(lspid) = 0; + + lsp = lsp_search (lspid, area->lspdb[level - 1]); + + if (lsp == NULL) + zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level); + + vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS); + vertex->lsp = lsp; + + listnode_add (spftree->paths, vertex); + +#ifdef EXTREME_DEBUG + zlog_info ("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; +} + +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 (node = listhead (list); node; nextnode (node)) { + vertex = getdata (node); + if (vertex->type != vtype) + continue; + switch (vtype) { + case VTYPE_ES: + case VTYPE_NONPSEUDO_IS: + if (memcmp ((u_char *)id, vertex->N.id, ISIS_SYS_ID_LEN) == 0) + return vertex; + break; + case VTYPE_PSEUDO_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: +#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 + */ +struct isis_vertex * +isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, + void *id, struct isis_adjacency *adj, u_int16_t cost, + int depth, int family) +{ + struct isis_vertex *vertex, *v; + struct listnode *node; +#ifdef EXTREME_DEBUG + u_char buff[BUFSIZ]; +#endif + + vertex = isis_vertex_new (id, vtype); + vertex->d_N = cost; + vertex->depth = depth; + + if (adj) + listnode_add (vertex->Adj_N, adj); +#ifdef EXTREME_DEBUG + zlog_info ("ISIS-Spf: add to TENT %s %s depth %d dist %d", + vtype2string(vertex->type), vid2string(vertex, buff), + vertex->depth, vertex->d_N); +#endif /* EXTREME_DEBUG */ + listnode_add (spftree->tents, vertex); + if (list_isempty (spftree->tents)) { + listnode_add (spftree->tents, vertex); + return vertex; + } + for (node = listhead (spftree->tents); node; nextnode (node)) { + v = getdata (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) { + /* Tie break, add according to type */ + while (v && v->d_N == vertex->d_N && v->type > vertex->type) { + if (v->type > vertex->type) { + break; + } + nextnode (node); + (node) ? (v = getdata (node)) : (v = NULL); + } + list_add_node_prev (spftree->tents, node, vertex); + break; + } else if (node->next == NULL) { + list_add_node_next (spftree->tents, node, vertex); + break; + } + } + return vertex; +} + +struct isis_vertex * +isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, + void *id, struct isis_adjacency *adj, u_int16_t cost, + int family) +{ + 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); + } + /* f) */ + else if (vertex->d_N > cost) { + listnode_delete (spftree->tents, vertex); + goto add2tent; + } + /* e) do nothing */ + return vertex; + } + + add2tent: + return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family); +} + +void +process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, + u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj, + int family) +{ + struct isis_vertex *vertex; +#ifdef EXTREME_DEBUG + u_char buff[255]; +#endif + + /* C.2.6 b) */ + if (dist > MAX_PATH_METRIC) + return; + /* c) */ + vertex = isis_find_vertex (spftree->paths, id, vtype); + if (vertex) { +#ifdef EXTREME_DEBUG + zlog_info ("ISIS-Spf: process_N %s %s dist %d already found from PATH", + 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_info ("ISIS-Spf: process_N %s %s dist %d", + vtype2string(vtype), vid2string(vertex, buff), dist); +#endif /* EXTREME_DEBUG */ + if (vertex->d_N == dist) { + if (adj) + listnode_add (vertex->Adj_N, adj); + /* 2) */ + if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) + remove_excess_adjs (vertex->Adj_N); + /* 3) */ + return; + } else if (vertex->d_N < dist) { + return; + /* 4) */ + } else { + listnode_delete (spftree->tents, vertex); + } + } + + isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family); + return; +} + +/* + * C.2.6 Step 1 + */ +int +isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, + uint16_t cost, uint16_t depth, int family) +{ + struct listnode *node, *fragnode = NULL; + u_int16_t dist; + struct is_neigh *is_neigh; + struct ipv4_reachability *ipreach; + enum vertextype vtype; + struct prefix prefix; +#ifdef HAVE_IPV6 + struct ipv6_reachability *ip6reach; +#endif /* HAVE_IPV6 */ + + + if (!lsp->adj) + return ISIS_WARNING; + if (lsp->tlv_data.nlpids == NULL || + !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" + " - do not process"); + return ISIS_WARNING; + } + + if (!ISIS_MASK_LSP_OL_BIT(lsp->lsp_header->lsp_bits)) { + if (lsp->tlv_data.is_neighs) { + for (node = listhead (lsp->tlv_data.is_neighs); node; nextnode (node)) { + is_neigh = getdata (node); + /* C.2.6 a) */ + /* Two way connectivity */ + if (!memcmp (is_neigh->neigh_id, isis->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, + lsp->adj, family); + } + } + if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) { + prefix.family = AF_INET; + for (node = listhead (lsp->tlv_data.ipv4_int_reachs); node; + nextnode (node)) { + ipreach = getdata (node); + dist = cost + ipreach->metrics.metric_default; + vtype = VTYPE_IPREACH_INTERNAL; + prefix.u.prefix4 = ipreach->prefix; + prefix.prefixlen = ip_masklen (ipreach->mask); + process_N (spftree, vtype, (void *)&prefix, dist, depth + 1, + lsp->adj, family); + } + } + + if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) { + prefix.family = AF_INET; + for (node = listhead (lsp->tlv_data.ipv4_ext_reachs); node; + nextnode (node)) { + ipreach = getdata (node); + dist = cost + ipreach->metrics.metric_default; + vtype = VTYPE_IPREACH_EXTERNAL; + prefix.u.prefix4 = ipreach->prefix; + prefix.prefixlen = ip_masklen (ipreach->mask); + process_N (spftree, vtype, (void *)&prefix, dist, depth + 1, + lsp->adj, family); + } + } +#ifdef HAVE_IPV6 + if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) { + prefix.family = AF_INET6; + for (node = listhead (lsp->tlv_data.ipv6_reachs); node; + nextnode (node)) { + ip6reach = getdata (node); + dist = cost + 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)); + process_N (spftree, vtype, (void *)&prefix, dist, depth + 1, + lsp->adj, family); + } + } +#endif /* HAVE_IPV6 */ + } + + if (fragnode == NULL) + fragnode = listhead (lsp->lspu.frags); + else + fragnode = nextnode (fragnode); + + if (fragnode) { + lsp = getdata (fragnode); + goto lspfragloop; + } + + return ISIS_OK; +} + +int +isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,struct isis_lsp *lsp, + uint16_t cost, uint16_t depth, int family) +{ + struct listnode *node, *fragnode = NULL; + struct is_neigh *is_neigh; + enum vertextype vtype; + + 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; + } + + for (node = (lsp->tlv_data.is_neighs ? + listhead (lsp->tlv_data.is_neighs) : NULL); + node; nextnode (node)) { + is_neigh = getdata (node); + vtype = LSP_PSEUDO_ID(is_neigh->neigh_id) ? VTYPE_PSEUDO_IS + : VTYPE_NONPSEUDO_IS; + /* Two way connectivity */ + if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) + continue; + if (isis_find_vertex (spftree->tents, (void *)is_neigh->neigh_id, vtype) + == NULL && + isis_find_vertex (spftree->paths, (void *)is_neigh->neigh_id, vtype) + == NULL) { + /* C.2.5 i) */ + isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, lsp->adj, + cost, depth, family); + } + } + + if (fragnode == NULL) + fragnode = listhead (lsp->lspu.frags); + else + fragnode = nextnode (fragnode); + + if (fragnode) { + lsp = getdata (fragnode); + goto pseudofragloop; + } + + + return ISIS_OK; +} + +int +isis_spf_preload_tent (struct isis_spftree *spftree, + struct isis_area *area, int level, int family) +{ + struct isis_vertex *vertex; + 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]; +#ifdef HAVE_IPV6 + struct prefix_ipv6 *ipv6; +#endif /* HAVE_IPV6 */ + + for (cnode = listhead (area->circuit_list); cnode; nextnode (cnode)) { + circuit = getdata (cnode); + if (circuit->state != C_STATE_UP) + continue; + if (!(circuit->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 (ipnode = (circuit->ip_addrs ? listhead (circuit->ip_addrs) : NULL); + ipnode; nextnode (ipnode)) { + ipv4 = getdata (ipnode); + prefix.u.prefix4 = ipv4->prefix; + prefix.prefixlen = ipv4->prefixlen; + isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, NULL, 0, + family); + } + } +#ifdef HAVE_IPV6 + if (family == AF_INET6) { + prefix.family = AF_INET6; + for (ipnode = (circuit->ipv6_non_link ? listhead + (circuit->ipv6_non_link) : NULL); ipnode; + nextnode (ipnode)) { + ipv6 = getdata (ipnode); + prefix.prefixlen = ipv6->prefixlen; + prefix.u.prefix6 = ipv6->prefix; + isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL, + &prefix, NULL, 0, family); + } + } +#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); + zlog_warn ("ISIS-Spf: no L%d adjacencies on circuit %s", + level, circuit->interface->name); + continue; + } + anode = listhead (adj_list); + while (anode) { + adj = getdata (anode); + 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->metrics[level - 1].metric_default, + family); + break; + case ISIS_SYSTYPE_IS: + case ISIS_SYSTYPE_L1_IS: + case ISIS_SYSTYPE_L2_IS: + vertex = + isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, + adj->sysid, adj, + circuit->metrics[level - 1].metric_default, + family); + 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, area->lspdb[level - 1]); + if (!lsp) + zlog_warn ("No lsp found for IS adjacency"); + /* else { + isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family); + } */ + break; + case ISIS_SYSTYPE_UNKNOWN: + default: + zlog_warn ("isis_spf_preload_tent unknow adj type"); + } + anode = nextnode (anode); + } + 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); + lsp = lsp_search (lsp_id, area->lspdb[level - 1]); + 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 for DR"); + } + if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { + zlog_warn ("ISIS-Spf: No lsp found for DR"); + } else { + isis_spf_process_pseudo_lsp + (spftree, lsp, circuit->metrics[level - 1].metric_default, 0, + family); + + } + } 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->metrics[level - 1].metric_default, + family); + 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, VTYPE_NONPSEUDO_IS, adj->sysid, adj, + circuit->metrics[level - 1].metric_default, + family); + break; + case ISIS_SYSTYPE_UNKNOWN: + default: + zlog_warn ("isis_spf_preload_tent unknow adj type"); + break; + } + } 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 + */ +void +add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, + struct isis_area *area) +{ + +#ifdef EXTREME_DEBUG + u_char buff[BUFSIZ]; +#endif /* EXTREME_DEBUG */ + listnode_add (spftree->paths, vertex); + +#ifdef EXTREME_DEBUG + zlog_info ("ISIS-Spf: added %s %s depth %d dist %d to PATHS", + 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, area); + else if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_info ("ISIS-Spf: no adjacencies do not install route"); + } + + return; +} + + +void +init_spt (struct isis_spftree *spftree) +{ + spftree->tents->del = spftree->paths->del = (void *)isis_vertex_del; + list_delete_all_node (spftree->tents); + list_delete_all_node (spftree->paths); + spftree->tents->del = spftree->paths->del = NULL; + + return; +} + +int +isis_run_spf (struct isis_area *area, int level, int family) +{ + int retval = ISIS_OK; + struct listnode *node; + struct isis_vertex *vertex; + struct isis_spftree *spftree = NULL; + u_char lsp_id[ISIS_SYS_ID_LEN + 2]; + struct isis_lsp *lsp; + + 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); + + /* + * C.2.5 Step 0 + */ + init_spt (spftree); + /* a) */ + isis_spf_add_self (spftree, area, level); + /* b) */ + retval = isis_spf_preload_tent (spftree, area, level, family); + + /* + * C.2.7 Step 2 + */ + if (listcount (spftree->tents) == 0) { + zlog_warn ("ISIS-Spf: TENT is empty"); + spftree->lastrun = time (NULL); + return retval; + } + + while (listcount (spftree->tents) > 0) { + node = listhead (spftree->tents); + vertex = getdata (node); + /* Remove from tent list */ + list_delete_node (spftree->tents, node); + if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) + continue; + add_to_paths (spftree, vertex, area); + if (vertex->type == VTYPE_PSEUDO_IS || + vertex->type == VTYPE_NONPSEUDO_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) { + if (LSP_PSEUDO_ID (lsp_id)) { + isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, + vertex->depth, family); + + } else { + isis_spf_process_lsp (spftree, lsp, vertex->d_N, vertex->depth, + family); + } + } else { + zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id)); + } + } + } + + thread_add_event (master, isis_route_validate, area, 0); + spftree->lastrun = time (NULL); + spftree->pending = 0; + + if (level == 1) + spftree->t_spf_periodic = thread_add_timer (master, + isis_run_spf_l1, area, + isis_jitter + (PERIODIC_SPF_INTERVAL, 10)); + else + spftree->t_spf_periodic = thread_add_timer (master, + isis_run_spf_l2, area, + isis_jitter + (PERIODIC_SPF_INTERVAL, 10)); + + return retval; +} + +int +isis_run_spf_l1 (struct thread *thread) +{ + struct isis_area *area; + int retval = ISIS_OK; + + area = THREAD_ARG(thread); + assert (area); + + 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_info ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", + area->area_tag); + } + + if (area->ip_circuits) + retval = isis_run_spf (area, 1, AF_INET); +#ifdef HAVE_IPV6 + if (area->ipv6_circuits) + retval = isis_run_spf (area, 1, AF_INET6); +#endif + return retval; +} + +int +isis_run_spf_l2 (struct thread *thread) +{ + struct isis_area *area; + int retval = ISIS_OK; + + area = THREAD_ARG(thread); + assert (area); + + 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_info ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", + area->area_tag); + } + + if (area->ip_circuits) + retval = isis_run_spf (area, 2, AF_INET); +#ifdef HAVE_IPV6 + if (area->ipv6_circuits) + retval = isis_run_spf (area, 2, AF_INET6); +#endif + + return retval; +} + +int +isis_spf_schedule (struct isis_area *area, int level) +{ + int retval = ISIS_OK; + struct isis_spftree *spftree = area->spftree[level - 1]; + time_t diff, now = time (NULL); + + if (spftree->pending) + return retval; + + diff = now - spftree->lastrun; + + /* FIXME: let's wait a minute before doing the SPF */ + if (now - isis->uptime < 60 || isis->uptime == 0) { + if (level == 1) + thread_add_timer (master, isis_run_spf_l1, area, + 60); + else + thread_add_timer (master, isis_run_spf_l2, area, + 60); + + spftree->pending = 1; + return retval; + } + if (spftree->t_spf_periodic) + thread_cancel (spftree->t_spf_periodic); + + if (diff < MINIMUM_SPF_INTERVAL) { + if (level == 1) + thread_add_timer (master, isis_run_spf_l1, area, + MINIMUM_SPF_INTERVAL - diff); + else + thread_add_timer (master, isis_run_spf_l2, area, + MINIMUM_SPF_INTERVAL - diff); + + spftree->pending = 1; + } else { + spftree->pending = 0; + retval = isis_run_spf (area, level, AF_INET); + } + + return retval; +} + +#ifdef HAVE_IPV6 +int +isis_spf_schedule6 (struct isis_area *area, int level) +{ + int retval = ISIS_OK; + struct isis_spftree *spftree = area->spftree6[level - 1]; + time_t diff, now = time (NULL); + + if (spftree->pending) + return retval; + + diff = now - spftree->lastrun; + + if (spftree->t_spf_periodic) + thread_cancel (spftree->t_spf_periodic); + + /* FIXME: let's wait a minute before doing the SPF */ + if (now - isis->uptime < 60 || isis->uptime == 0) { + if (level == 1) + thread_add_timer (master, isis_run_spf_l1, area, + 60); + else + thread_add_timer (master, isis_run_spf_l2, area, + 60); + + spftree->pending = 1; + return retval; + } + + + if (diff < MINIMUM_SPF_INTERVAL) { + if (level == 1) + thread_add_timer (master, isis_run_spf_l1, area, + MINIMUM_SPF_INTERVAL - diff); + else + thread_add_timer (master, isis_run_spf_l2, area, + MINIMUM_SPF_INTERVAL - diff); + + spftree->pending = 1; + } else { + spftree->pending = 0; + retval = isis_run_spf (area, level, AF_INET6); + } + + return retval; +} + +#endif + +void +isis_print_paths (struct vty *vty, struct list *paths) +{ + struct listnode *node, *anode; + struct isis_vertex *vertex; + struct isis_dynhn *dyn, *nh_dyn = NULL; + struct isis_adjacency *adj; +#ifdef EXTREME_DEBUG + u_char buff[255]; +#endif + + vty_out (vty, "System Id Metric Next-Hop" + " Interface SNPA%s", VTY_NEWLINE); + for (node = listhead (paths); node; nextnode (node)) { + vertex = getdata (node); + if (vertex->type != VTYPE_NONPSEUDO_IS) + continue; + if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0) { + vty_out (vty, "%s --%s", host.name, VTY_NEWLINE); + } else { + dyn = dynhn_find_by_id ((u_char *)vertex->N.id); + anode = listhead (vertex->Adj_N); + adj = getdata (anode); + if (adj) { + nh_dyn = dynhn_find_by_id (adj->sysid); + vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s", + (dyn != NULL) ? dyn->name.name : + (u_char *)rawlspid_print ((u_char *)vertex->N.id), + vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name : + (u_char *)rawlspid_print (adj->sysid), + adj->circuit->interface->name, + snpa_print (adj->snpa), VTY_NEWLINE); + } else { + vty_out (vty, "%s %u %s", dyn ? dyn->name.name : + (u_char *)rawlspid_print (vertex->N.id), + vertex->d_N, VTY_NEWLINE); + } + + } +#if 0 + vty_out (vty, "%s %s %u %s", vtype2string(vertex->type), + vid2string(vertex, buff), vertex->d_N, VTY_NEWLINE); +#endif + } + + +} + +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 (node = listhead (isis->area_list); node; nextnode (node)) { + area = getdata (node); + + 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); + } +#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); + } +#endif /* HAVE_IPV6 */ + } + } + + 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 (node = listhead (isis->area_list); node; nextnode (node)) { + area = getdata (node); + + 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); + } +#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); + } +#endif /* HAVE_IPV6 */ + } + + + 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 (node = listhead (isis->area_list); node; nextnode (node)) { + area = getdata (node); + + 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); + } +#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); + } +#endif /* HAVE_IPV6 */ + } + + + 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); +} diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h new file mode 100644 index 00000000..59e4b6b5 --- /dev/null +++ b/isisd/isis_spf.h @@ -0,0 +1,85 @@ +/* + * 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_NONPSEUDO_IS, + VTYPE_ES, + VTYPE_IPREACH_INTERNAL, + VTYPE_IPREACH_EXTERNAL +#ifdef HAVE_IPV6 + , + VTYPE_IP6REACH_INTERNAL, + VTYPE_IP6REACH_EXTERNAL +#endif /* HAVE_IPV6 */ +}; + +/* + * Triple <N, d(N), {Adj(N)}> + */ +struct isis_vertex +{ + enum vertextype type; + + union { + u_char id [ISIS_SYS_ID_LEN + 1]; + struct prefix prefix; + } N; + + struct isis_lsp *lsp; + 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)} */ +}; + + +struct isis_spftree +{ + struct thread *t_spf_periodic; /* periodic spf threads */ + time_t lastrun; /* for scheduling */ + int pending; /* already scheduled */ + struct list *paths; /* the SPT */ + struct list *tents; /* TENT */ + + u_int32_t timerun; /* statistics */ +}; + +void spftree_area_init (struct isis_area *area); +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 */ + + + + + + + + diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c new file mode 100644 index 00000000..b51cee91 --- /dev/null +++ b/isisd/isis_tlv.c @@ -0,0 +1,1014 @@ +/* + * 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 <zebra.h> +#include <net/ethernet.h> + +#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" + +extern struct isis *isis; + +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->lan_neighs) { + list_delete (tlvs->lan_neighs); + } + if (tlvs->prefix_neighs) { + list_delete (tlvs->prefix_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 */ + 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_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 *pnt = stream; + + *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_info ("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_info ("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_info ("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_info ("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_info ("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_info ("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_info ("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_info ("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_info ("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_info ("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; + zlog_info ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag, + inet_ntoa (*ipv4_addr), pnt); + 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_info ("ISIS-TLV (%s): IS-IS Authentication Information", + areatag); +#endif + if (*expected & TLVFLAG_AUTH_INFO) { + tlvs->auth_info.type = *pnt; + pnt++; + memcpy (tlvs->auth_info.passwd, pnt, length - 1); + pnt += length - 1; + } + else { + pnt += length; + } + break; + + case DYNAMIC_HOSTNAME: + *found |= TLVFLAG_DYN_HOSTNAME; +#ifdef EXTREME_TLV_DEBUG + zlog_info ("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_info ("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_info ("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_TE_IPV4_REACHABILITY; +#ifdef EXTREME_TLV_DEBUG + zlog_info ("ISIS-TLV (%s): IPv4 external Reachability length %d", + areatag, + length); +#endif /* EXTREME_TLV_DEBUG */ + if (*expected & TLVFLAG_TE_IPV4_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_info ("ISIS-TLV (%s): IPv4 extended Reachability length %d", + areatag, + length); +#endif /* EXTREME_TLV_DEBUG */ + if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) { + while (length > value_len) { + te_ipv4_reach = (struct te_ipv4_reachability*)pnt; + 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); + } + } + else { + pnt += length; + } + break; + +#ifdef HAVE_IPV6 + case IPV6_ADDR: + /* +-------+-------+-------+-------+-------+-------+-------+-------+ + * + IP version 6 address + 16 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * : : + */ + *found |= TLVFLAG_IPV6_ADDR; +#ifdef EXTREME_TLV_DEBUG + zlog_info ("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; + if (*expected & TLVFLAG_IPV6_REACHABILITY) { + while (length > value_len) { + ipv6_reach = (struct ipv6_reachability*)pnt; + 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); + } + } else { + pnt += length; + } + 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; + } + } else { + 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_SIZE (stream) - stream_get_putp (stream) < len + 2) { + zlog_warn ("No room for TLV of type %d", tag); + return ISIS_WARNING; + } + + stream_putc (stream, tag); /* TAG */ + stream_putc (stream, len); /* LENGTH */ + stream_put (stream, value, (int)len); /* VALUE */ + +#ifdef EXTREME_DEBUG + zlog_info ("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 (node = listhead (area_addrs); node; nextnode (node)) { + area_addr = getdata (node); + 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 (node = listhead (is_neighs); node; nextnode (node)) { + is_neigh = getdata (node); + 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_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 (node = listhead (lan_neighs); node; nextnode (node)) { + snpa = getdata (node); + 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); +} + + +/* + u_char value[255]; + u_char *pos = value; + + if (circuit->ip_router) { + *pos = (u_char)NLPID_IP; + pos ++; + } + if (circuit->ipv6_router) { + *pos = (u_char)NLPID_IPV6; + pos ++; + } +*/ + +int +tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream) +{ + + return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, + nlpids->nlpids, stream); +} + +int tlv_add_authinfo (char auth_type, char auth_len, char *auth_value, + struct stream *stream) +{ + u_char value[255]; + u_char *pos = value; + pos++; + 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 (node = listhead (ip_addrs); node; nextnode (node)) { + ipv4 = getdata (node); + if (pos - value + IPV4_MAX_BYTELEN > 255) { + retval = add_tlv (IPV4_ADDR, pos - value, value, stream); + if (retval != ISIS_OK) + return retval; + pos = value; + } + *(u_int32_t*)pos = ipv4->prefix.s_addr; + pos += IPV4_MAX_BYTELEN; + } + + return add_tlv (IPV4_ADDR, 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 (node = listhead (lsps); node; nextnode (node)) { + lsp = getdata (node); + 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 (node = listhead (ipv4_reachs); node; nextnode (node)) { + reach = getdata (node); + 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); +} + +#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 (node = listhead (ipv6_addrs); node; nextnode (node)) { + ipv6 = getdata (node); + 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 (node = listhead (ipv6_reachs); node; nextnode (node)) { + ip6reach = getdata (node); + 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) +{ + unsigned long putp, endp; + int fullpads, i, left; + + /* + * How many times can we add full padding ? + */ + fullpads = (STREAM_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; + endp = stream_get_endp (stream); + putp = stream_get_putp (stream); + if (putp != endp) + zlog_warn ("tvl_add_padding endp %ld while putp %ld", endp, putp); + stream_set_putp (stream, putp + 255); /* VALUE */ + stream->endp = stream->putp; + } + + left = STREAM_SIZE(stream) - stream_get_putp (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_set_putp (stream, stream_get_putp (stream) + left - 2); + stream->endp = stream->putp; + + return ISIS_OK; + + err: + zlog_warn ("tlv_add_padding(): no room for tlv"); + return ISIS_WARNING; +} diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h new file mode 100644 index 00000000..79c0c46f --- /dev/null +++ b/isisd/isis_tlv.h @@ -0,0 +1,268 @@ +/* + * 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 + +/* + * Structures found in TLV's. + * this header is fully complient with + * draft-ietf-isis-wg-tlv-codepoints-02.txt + 1. TLV Codepoints reserved + ____________________________________________________ + Name Value IIH LSP SNP Status + ____________________________________________________ + + Area Addresses 1 y y n ISO 10589 + IIS Neighbors 2 n y n ISO 10589 + ES Neighbors 3 n y n ISO 10589 + Part. DIS 4 n y n ISO 10589 + Prefix Neighbors 5 n y n ISO 10589 + IIS Neighbors 6 y n n ISO 10589 + Padding 8 y n n ISO 10589 + LSP Entries 9 n n y ISO 10589 + Authentication 10 y y y ISO 10589 + Opt. Checksum 12 y n y IETF-draft + LSPBufferSize 14 n y n ISO 10589 Rev 2 Draft + TE IIS Neigh. 22 n y n IETF-draft + DECnet Phase IV 42 y n n DEC (ancient) + IP Int. Reach 128 n y n RFC 1195 + Prot. Supported 129 y y n RFC 1195 + IP Ext. Address 130 n y n RFC 1195 + IDRPI 131 n y y RFC 1195 + IP Intf. Address 132 y y n RFC 1195 + Illegal 133 n n n RFC 1195 (not used) + Router ID 134 n y n IETF-draft + TE IP. Reach 135 n y n IETF-draft + Dynamic Name 137 n y n RFC 2763 + Nortel Proprietary 176 n y n + Nortel Proprietary 177 n y n + Restart TLV 211 y n n IETF-draft + MT-ISN 222 n y n IETF-draft + M-Topologies 229 y y n IETF-draft + IPv6 Intf. Addr. 232 y y n IETF-draft + MT IP. Reach 235 n y n IETF-draft + IPv6 IP. Reach 236 n y n IETF-draft + MT IPv6 IP. Reach 237 n y n IETF-draft + P2P Adjacency State 240 y n n IETF-draft + + */ + +#define AREA_ADDRESSES 1 +#define IS_NEIGHBOURS 2 +#define ES_NEIGHBOURS 3 +#define PARTITION_DESIG_LEVEL2_IS 4 +#define PREFIX_NEIGHBOURS 5 +#define LAN_NEIGHBOURS 6 +#define PADDING 8 +#define LSP_ENTRIES 9 +#define AUTH_INFO 10 +#define CHECKSUM 12 +#define TE_IS_NEIGHBOURS 22 +#define IPV4_INT_REACHABILITY 128 +#define IPV4_EXT_REACHABILITY 130 +#define PROTOCOLS_SUPPORTED 129 +#define IDRP_INFO 131 +#define IPV4_ADDR 132 +#define TE_ROUTER_ID 134 +#define TE_IPV4_REACHABILITY 135 +#define DYNAMIC_HOSTNAME 137 +#define IPV6_REACHABILITY 236 +#define IPV6_ADDR 232 +#define WAY3_HELLO 240 + +#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 + +/* 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; +}; + +/* 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]; +}; + +/* 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)); + +/* 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]; +}; +#endif /* HAVE_IPV6 */ + +/* 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 + +/* + * Pointer to each tlv type, filled by parse_tlvs() + */ +struct tlvs { + 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 checksum *checksum; + struct nlpids *nlpids; + struct list *ipv4_addrs; + struct list *ipv4_int_reachs; + struct list *ipv4_ext_reachs; + struct list *te_ipv4_reachs; + struct hostname *hostname; + struct te_router_id *router_id; +#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) + +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); +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_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 (char auth_type, char authlen, char *auth_value, + struct stream *stream); +int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream); +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); +#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 */ + + + diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c new file mode 100644 index 00000000..d9179f91 --- /dev/null +++ b/isisd/isis_zebra.c @@ -0,0 +1,592 @@ +/* + * 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 <zebra.h> +#include <net/ethernet.h> + +#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/isis_constants.h" +#include "isisd/isis_common.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_csm.h" +#include "isisd/isis_route.h" +#include "isisd/isis_zebra.h" + +struct zclient *zclient = NULL; + +extern struct thread_master *master; + +int +isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + + zlog_info ("Zebra I/F add: %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + if (if_is_up (ifp)) + isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); + + return 0; +} + +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_up (ifp)) + zlog_warn ("Zebra: got delete of %s, but interface is still up", + ifp->name); + + zlog_info ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + if_delete (ifp); + + isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); + + return 0; +} + +struct interface * +zebra_interface_if_lookup (struct stream *s) +{ + struct interface *ifp; + u_char ifname_tmp[INTERFACE_NAMSIZ]; + + /* Read interface name. */ + stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); + + /* Lookup this by interface index. */ + ifp = if_lookup_by_name (ifname_tmp); + + /* If such interface does not exist, indicate an error */ + if (!ifp) + return NULL; + + return ifp; +} + +void +zebra_interface_if_set_value (struct stream *s, struct interface *ifp) +{ + /* Read interface's index. */ + ifp->ifindex = stream_getl (s); + + /* Read interface's value. */ + ifp->flags = stream_getl (s); + ifp->metric = stream_getl (s); + ifp->mtu = stream_getl (s); + ifp->bandwidth = stream_getl (s); +} + +int +isis_zebra_if_state_up (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_if_lookup (zclient->ibuf); + + if (!ifp) + return 0; + + if (if_is_up (ifp)) { + zebra_interface_if_set_value (zclient->ibuf, ifp); + isis_circuit_update_params (circuit_scan_by_ifp (ifp), ifp); + return 0; + } + + zebra_interface_if_set_value (zclient->ibuf, ifp); + isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); + + return 0; +} + + +int +isis_zebra_if_state_down (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_if_lookup (zclient->ibuf); + + if (ifp == NULL) + return 0; + + if (if_is_up (ifp)) { + zebra_interface_if_set_value (zclient->ibuf, ifp); + isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); + } + + return 0; +} + +int +isis_zebra_if_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + struct prefix *p; + u_char buf[BUFSIZ]; + + c = zebra_interface_address_add_read (zclient->ibuf); + + if (c == NULL) + return 0; + + p = c->address; + + prefix2str (p, buf, BUFSIZ); +#ifdef EXTREME_DEBUG + if (p->family == AF_INET) + zlog_info ("connected IP address %s", buf); +#ifdef HAVE_IPV6 + if (p->family == AF_INET6) + zlog_info ("connected IPv6 address %s", buf); +#endif /* HAVE_IPV6 */ +#endif /* EXTREME_DEBUG */ + isis_circuit_add_addr (circuit_scan_by_ifp (c->ifp), c); + + return 0; +} + +int +isis_zebra_if_address_del (int command, struct zclient *client, + zebra_size_t length) +{ + struct connected *c; + struct interface *ifp; + + c = zebra_interface_address_delete_read (zclient->ibuf); + + if (c == NULL) + return 0; + + ifp = c->ifp; + + connected_free (c); + + isis_circuit_del_addr (circuit_scan_by_ifp (ifp), c); + + return 0; +} + +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_SYNC)) + return; + + if (zclient->redist[ZEBRA_ROUTE_ISIS]) { + message = 0; + flags = 0; + + SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); + SET_FLAG (message, ZAPI_MESSAGE_METRIC); + SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); + + stream = zclient->obuf; + stream_reset (stream); + /* Length place holder. */ + stream_putw (stream, 0); + /* command */ + stream_putc (stream, ZEBRA_IPV4_ROUTE_ADD); + /* type */ + stream_putc (stream, ZEBRA_ROUTE_ISIS); + /* flags */ + stream_putc (stream, flags); + /* message */ + stream_putc (stream, message); + /* 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 (node = listhead (route_info->nexthops); node; nextnode (node)) { + nexthop = getdata (node); + /* 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 (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + stream_putc (stream, route_info->depth); + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + stream_putl (stream, route_info->cost); + + stream_putw_at (stream, 0, stream_get_endp (stream)); + writen (zclient->sock, stream->data, stream_get_endp (stream)); + } +} + +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; + prefix4.family = AF_INET; + prefix4.prefixlen = prefix->prefixlen; + prefix4.prefix = prefix->u.prefix4; + zapi_ipv4_delete (zclient, &prefix4, &api); + } + + 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_SYNC)) + return; + + api.type = ZEBRA_ROUTE_ISIS; + api.flags = 0; + api.message = 0; + 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 (node = listhead (route_info->nexthops6); node; nextnode (node)) { + nexthop6 = getdata (node); + + 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_add (zclient, &prefix6, &api); + SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + } + + XFREE (MTYPE_ISIS_TMP, nexthop_list); + XFREE (MTYPE_ISIS_TMP, ifindex_list); + + return; +} + +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_SYNC)) + return; + + api.type = ZEBRA_ROUTE_ISIS; + api.flags = 0; + api.message = 0; + 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 (node = listhead (route_info->nexthops6); node; nextnode (node)) { + nexthop6 = getdata (node); + + 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_delete (zclient, &prefix6, &api); + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + } + + 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; +} + + +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) { + zlog_info ("IPv4 Route add from Z"); + } + + return 0; +} + + +int +isis_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + + return 0; +} + +#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; +} + +int +isis_redistribute_default_set(int routetype, int metric_type, int metric_value) +{ + return 0; +} + + +void +isis_zebra_init () +{ + + zclient = zclient_new (); + zclient_init (zclient, ZEBRA_ROUTE_ISIS); + 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; +} + +void +isis_zebra_finish () +{ + + zclient_stop (zclient); + zclient_free (zclient); + zclient = (struct zclient *) NULL; + + return; +} + + + + + + + diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h new file mode 100644 index 00000000..fabf7200 --- /dev/null +++ b/isisd/isis_zebra.h @@ -0,0 +1,33 @@ +/* + * 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_finish (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 */ diff --git a/isisd/isisd.c b/isisd/isisd.c new file mode 100644 index 00000000..8794a12c --- /dev/null +++ b/isisd/isisd.c @@ -0,0 +1,1989 @@ +/* + * 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 <string.h> +#include <zebra.h> +#include <net/ethernet.h> + +#include "thread.h" +#include "vty.h" +#include "command.h" +#include "log.h" +#include "memory.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_circuit.h" +#include "isisd/isis_flags.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; +struct thread_master *master; + + +void +isis_new (unsigned long process_id) +{ + + isis = XMALLOC (MTYPE_ISIS, sizeof(struct isis)); + bzero (isis, sizeof (struct isis)); + /* + * Default values + */ + isis->max_area_addrs = 3; + + isis->process_id = process_id; + 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 */ + /* + * uncomment the next line for full debugs + */ + /* isis->debugs = 0xFFFF; */ +} + +struct isis_area * +isis_area_create () +{ + + struct isis_area *area; + + area = XMALLOC (MTYPE_ISIS_AREA, sizeof (struct isis_area)); + memset (area, 0, 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 + */ + area->lspdb[0] = lsp_db_init (); + area->lspdb[1] = lsp_db_init (); + + spftree_area_init (area); + area->route_table = route_table_init (); +#ifdef HAVE_IPV6 + area->route_table6 = route_table_init (); +#endif /* HAVE_IPV6 */ + area->circuit_list = list_new (); + area->area_addrs = list_new (); + area->t_tick = thread_add_timer (master, lsp_tick, area, 1); + area->flags.maxindex = -1; + /* + * Default values + */ + area->max_lsp_lifetime[0] = MAX_AGE; /* 1200 */ + area->max_lsp_lifetime[1] = MAX_AGE; /* 1200 */ + area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT; + area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT; + area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900 */ + area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900 */ + area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; + area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; + area->dynhostname = 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; + + return area; +} + +struct isis_area * +isis_area_lookup (char *area_tag) +{ + struct isis_area *area; + struct listnode *node; + + LIST_LOOP (isis->area_list, area, node) + 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, 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->area_tag = strdup (area_tag); + listnode_add (isis->area_list, area); + + zlog_info ("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, char *area_tag) +{ + + struct isis_area *area; + struct listnode *node; + struct isis_circuit *circuit; + + area = isis_area_lookup (area_tag); + + if (area == NULL) { + vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (area->circuit_list) { + node = listhead (area->circuit_list); + while (node) { + circuit = getdata (node); + nextnode (node); + isis_circuit_del (circuit); + } + list_delete (area->circuit_list); + } + listnode_delete (isis->area_list, area); + if (area->t_tick) + thread_cancel (area->t_tick); + if (area->t_remove_aged) + thread_cancel (area->t_remove_aged); + if (area->t_lsp_refresh[0]) + thread_cancel (area->t_lsp_refresh[0]); + if (area->t_lsp_refresh[1]) + thread_cancel (area->t_lsp_refresh[1]); + + XFREE (MTYPE_ISIS_AREA, area); + + return CMD_SUCCESS; +} + +int +area_net_title (struct vty *vty , 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_WARNING; + } + + /* 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_WARNING; + } + + 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_info ("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) { + zlog_warn ("area address must be at least 8..20 octets long (%d)", + addr->addr_len); + XFREE (MTYPE_ISIS_AREA_ADDR, addr); + return CMD_WARNING; + } + + if (isis->sysid_set == 0) { + /* + * First area address - get the SystemID for this router + */ + memcpy (isis->sysid, GETSYSID(addr, ISIS_SYS_ID_LEN), ISIS_SYS_ID_LEN); + isis->sysid_set = 1; + zlog_info ("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), + 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_WARNING; + } + + /* now we see that we don't already have this address */ + LIST_LOOP (area->area_addrs, addrp, node) { + if ((addrp->addr_len+ ISIS_SYS_ID_LEN + 1) == (addr->addr_len)) { + 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 + 1); + listnode_add (area->area_addrs, addr); + + /* only now we can safely generate our LSPs for this area */ + if (listcount(area->area_addrs) > 0) { + lsp_l1_generate (area); + lsp_l2_generate (area); + } + + return CMD_SUCCESS; +} + +int +area_clear_net_title (struct vty *vty, 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_WARNING; + } + + 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_WARNING; + } + + memcpy(addr.area_addr, buff, (int)addr.addr_len); + + LIST_LOOP (area->area_addrs, addrp, node) + if (addrp->addr_len == 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_WARNING; + } + + listnode_delete (area->area_addrs, addrp); + + return CMD_SUCCESS; +} + + +/* + * 'show clns neighbors' command + */ + +int +show_clns_neigh (struct vty *vty, char detail) +{ + struct listnode *node_area, *node_circ; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *db; + int i; + + if (!isis) { + vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + for (node_area = listhead (isis->area_list); node_area; + nextnode (node_area)) { + area = getdata (node_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 (node_circ = listhead (area->circuit_list); node_circ; + nextnode (node_circ)) { + circuit = getdata (node_circ); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) { + for (i = 0; i < 2; i++) { + db = circuit->u.bc.adjdb[i]; + if (db && db->count) { + if (detail == ISIS_UI_LEVEL_BRIEF) + isis_adjdb_iterate (db, (void (*) (struct isis_adjacency *, + void *)) + isis_adj_print_vty, vty); + if (detail == ISIS_UI_LEVEL_DETAIL) + isis_adjdb_iterate (db, (void (*) (struct isis_adjacency *, + void *)) + isis_adj_print_vty_detail, vty); + if (detail == ISIS_UI_LEVEL_EXTENSIVE) + isis_adjdb_iterate (db, (void (*) (struct isis_adjacency *, + void *)) + isis_adj_print_vty_extensive, vty); + } + } + } else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) { + if (detail==ISIS_UI_LEVEL_BRIEF) + isis_adj_p2p_print_vty (circuit->u.p2p.neighbor, vty); + if (detail==ISIS_UI_LEVEL_DETAIL) + isis_adj_p2p_print_vty_detail (circuit->u.p2p.neighbor, vty); + if (detail==ISIS_UI_LEVEL_EXTENSIVE) + isis_adj_p2p_print_vty_extensive (circuit->u.p2p.neighbor, vty); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_clns_neighbors, + show_clns_neighbors_cmd, + "show clns neighbors", + SHOW_STR + "clns network information\n" + "CLNS neighbor adjacencies\n") +{ + return show_clns_neigh(vty, ISIS_UI_LEVEL_BRIEF); +} + +ALIAS (show_clns_neighbors, + show_isis_neighbors_cmd, + "show isis neighbors", + SHOW_STR + "IS-IS network information\n" + "IS-IS neighbor adjacencies\n") + +DEFUN (show_clns_neighbors_detail, + show_clns_neighbors_detail_cmd, + "show clns neighbors detail", + SHOW_STR + "clns network information\n" + "CLNS neighbor adjacencies\n" + "show detailed information\n") +{ + return show_clns_neigh(vty, ISIS_UI_LEVEL_DETAIL); +} + +ALIAS (show_clns_neighbors_detail, + show_isis_neighbors_detail_cmd, + "show isis neighbors detail", + SHOW_STR + "IS-IS network information\n" + "IS-IS neighbor adjacencies\n" + "show detailed information\n") + +/* + * '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); + +} + +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; +} + +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 (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; +} + + +DEFUN (show_database, + show_database_cmd, + "show isis database", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n") +{ + struct listnode *node; + struct isis_area *area; + int level,lsp_count; + + if (isis->area_list->count == 0) + return CMD_SUCCESS; + + for (node = listhead (isis->area_list); node; nextnode (node)) { + area = getdata (node); + 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) { + vty_out (vty,"IS-IS Level-%d link-state database:%s", level+1, + VTY_NEWLINE); + + lsp_count = lsp_print_all (vty, area->lspdb[level], + ISIS_UI_LEVEL_BRIEF, + area->dynhostname); + + vty_out (vty,"%s %u LSPs%s%s", + VTY_NEWLINE, + lsp_count, + VTY_NEWLINE, + VTY_NEWLINE); + } + } + } + + return CMD_SUCCESS; +} + + +DEFUN (show_database_detail, + show_database_detail_cmd, + "show isis database detail", + SHOW_STR + "IS-IS information\n" + "IS-IS link state database\n") +{ + struct listnode *node; + struct isis_area *area; + int level, lsp_count; + + if (isis->area_list->count == 0) + return CMD_SUCCESS; + + for (node = listhead (isis->area_list); node; nextnode (node)) { + area = getdata (node); + 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) { + vty_out (vty,"IS-IS Level-%d Link State Database:%s", level+1, + VTY_NEWLINE); + + lsp_count = lsp_print_all (vty, area->lspdb[level], + ISIS_UI_LEVEL_DETAIL, + area->dynhostname); + + vty_out (vty,"%s %u LSPs%s%s", + VTY_NEWLINE, + lsp_count, + VTY_NEWLINE, + VTY_NEWLINE); + } + } + } + + return CMD_SUCCESS; +} + +/* + * '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, + area_passwd_cmd, + "area-password WORD", + "Configure the authentication password for an area\n" + "Area password\n" ) +{ + struct isis_area *area; + int len; + + area = vty->index; + + if (!area) { + vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + len = strlen (argv[0]); + if (len > 254) { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_WARNING; + } + area->area_passwd.len = (u_char)len; + area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; + strncpy (area->area_passwd.passwd, argv[0], 255); + + return CMD_SUCCESS; +} + +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, "Cant find IS-IS instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + memset (&area->area_passwd, 0, sizeof (struct isis_passwd)); + + return CMD_SUCCESS; +} + + +DEFUN (domain_passwd, + domain_passwd_cmd, + "domain-password WORD", + "Set the authentication password for a routing domain\n" + "Routing domain password\n" ) +{ + struct isis_area *area; + int len; + + area = vty->index; + + if (!area) { + vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + len = strlen (argv[0]); + if (len > 254) { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_WARNING; + } + area->domain_passwd.len = (u_char)len; + area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; + strncpy (area->domain_passwd.passwd, argv[0], 255); + + return CMD_SUCCESS; +} + + +DEFUN (no_domain_passwd, + no_domain_passwd_cmd, + "no domain-password WORD", + NO_STR + "Set the authentication password for a routing domain\n") +{ + struct isis_area *area; + + area = vty->index; + + if (!area) { + vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + memset (&area->domain_passwd, 0, sizeof (struct isis_passwd)); + + 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, "Cant find IS-IS instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + 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 default. Which is level-1-2 on first + * circuit for the area level-1 for the rest + */ + if (getdata (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; +} + +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; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + area->lsp_gen_interval[0] = interval; + area->lsp_gen_interval[1] = interval; + + return CMD_SUCCESS; +} + +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; + + area = vty->index; + assert (area); + + area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT; + area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT; + + return CMD_SUCCESS; +} + +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; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + area->lsp_gen_interval[0] = interval; + + return CMD_SUCCESS; +} + +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; + + area = vty->index; + assert (area); + + area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT; + + return CMD_SUCCESS; +} + +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; + int interval; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + area->lsp_gen_interval[1] = interval; + + return CMD_SUCCESS; +} + +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; + int interval; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT; + + return CMD_SUCCESS; +} + +ALIAS (no_lsp_gen_interval_l2, + no_lsp_gen_interval_l2_arg_cmd, + "no lsp-gen-interval level-2 <1-120>", + NO_STR + "Minimum interval between regenerating same LSP\n" + "Set interval for level 2 only\n" + "Minimum interval in seconds\n" + ) + + +DEFUN (metric_style, + metric_style_cmd, + "metric-style (narrow|wide)", + "Use old-style (ISO 10589) or new-style packet formats\n" + "Use old style of TLVs with narrow metric\n" + "Use new style of TLVs to carry wider metric\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + if (!strcmp(argv[0],"wide")) + area->newmetric = 1; + else + area->newmetric = 0; + + return CMD_SUCCESS; +} + +DEFUN (no_metric_style, + no_metric_style_cmd, + "no metric-style (narrow|wide)", + NO_STR + "Use old-style (ISO 10589) or new-style packet formats\n" + "Use old style of TLVs with narrow metric\n" + "Use new style of TLVs to carry wider metric\n") +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + if (!strcmp(argv[0],"wide")) + area->newmetric = 0; + else + area->newmetric = 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); + + area->dynhostname = 1; + + 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); + + area->dynhostname = 0; + + return CMD_SUCCESS; +} + +DEFUN (spf_interval, + spf_interval_cmd, + "spf-interval <1-120>", + "Minimum interval between SPF calculations" + "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") + + +#ifdef TOPOLOGY_GENERATE +DEFUN (topology_generate_grid, + topology_generate_grid_cmd, + "topology generate grid <1-100> <1-100> <1-65000> [param] [param] " + "[param]", + "Topology for IS-IS\n" + "Topology for IS-IS\n" + "Topology grid for IS-IS\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); + } + + return CMD_SUCCESS; +} + +DEFUN (show_isis_topology, + show_isis_topology_cmd, + "show isis topology", + SHOW_STR + "clns network information\n" + "CLNS neighbor adjacencies\n") +{ + struct isis_area *area; + struct listnode *node; + struct listnode *node2; + struct arc *arc; + LIST_LOOP (isis->area_list, area, node) { + if (area->topology) { + vty_out (vty, "Topology for isis area:%s%s",area->area_tag, VTY_NEWLINE); + LIST_LOOP (area->topology, arc, node2) { + vty_out (vty, "a %ld %ld %ld%s",arc->from_node, arc->to_node, + arc->distance, VTY_NEWLINE); + } + } + } + return CMD_SUCCESS; +} + +/* + * 'topology base-is' command + */ +DEFUN (topology_baseis , + topology_baseis_cmd, + "topology base-is WORD", + "Topology for IS-IS\n" + "Topology for IS-IS\n" + "A Network IS Base for this topology" + "XX.XXXX.XXXX.XX 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; +} + +/* + * 'no net' command + */ +DEFUN (no_topology_baseis, + no_topology_baseis_cmd, + "no topology base-is WORD", + NO_STR + "A Network Entity Title for this process (OSI only)" + "XX.XXXX. ... .XXX.XX 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; +} + +#endif /* TOPOLOGY_GENERATE */ + +DEFUN (lsp_lifetime, + lsp_lifetime_cmd, + "lsp-lifetime <380-65535>", + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n" + ) +{ + struct isis_area *area; + uint16_t interval; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + + if (interval < ISIS_MIN_LSP_LIFETIME) { + vty_out (vty, "LSP lifetime (%us) below %us%s", + interval, + ISIS_MIN_LSP_LIFETIME, + VTY_NEWLINE); + + return CMD_WARNING; + } + + + area->max_lsp_lifetime[0] = interval; + area->max_lsp_lifetime[1] = interval; + area->lsp_refresh[0] = interval-300; + area->lsp_refresh[1] = interval-300; + + if (area->t_lsp_refresh[0]) { + thread_cancel (area->t_lsp_refresh[0]); + thread_execute (master, lsp_refresh_l1, area, 0); + } + + if (area->t_lsp_refresh[1]) { + thread_cancel (area->t_lsp_refresh[1]); + thread_execute (master, lsp_refresh_l2, area, 0); + } + + + return CMD_SUCCESS; +} + +DEFUN (no_lsp_lifetime, + no_lsp_lifetime_cmd, + "no lsp-lifetime", + NO_STR + "LSP lifetime in seconds\n" + ) +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */ + area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */ + area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */ + area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */ + + return CMD_SUCCESS; +} + +ALIAS (no_lsp_lifetime, + no_lsp_lifetime_arg_cmd, + "no lsp-lifetime <380-65535>", + NO_STR + "Maximum LSP lifetime\n" + "LSP lifetime in seconds\n" + ) + +DEFUN (lsp_lifetime_l1, + lsp_lifetime_l1_cmd, + "lsp-lifetime level-1 <380-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; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + + if (interval < ISIS_MIN_LSP_LIFETIME) { + vty_out (vty, "Level-1 LSP lifetime (%us) below %us%s", + interval, + ISIS_MIN_LSP_LIFETIME, + VTY_NEWLINE); + + return CMD_WARNING; + } + + + area->max_lsp_lifetime[0] = interval; + area->lsp_refresh[0] = interval-300; + + return CMD_SUCCESS; +} + +DEFUN (no_lsp_lifetime_l1, + no_lsp_lifetime_l1_cmd, + "no lsp-lifetime level-1", + NO_STR + "LSP lifetime for Level 1 only in seconds\n" + ) +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */ + area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */ + + return CMD_SUCCESS; +} + +ALIAS (no_lsp_lifetime_l1, + no_lsp_lifetime_l1_arg_cmd, + "no lsp-lifetime level-1 <380-65535>", + NO_STR + "Maximum LSP lifetime for Level 1 only\n" + "LSP lifetime for Level 1 only in seconds\n" + ) + +DEFUN (lsp_lifetime_l2, + lsp_lifetime_l2_cmd, + "lsp-lifetime level-2 <380-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; + + area = vty->index; + assert (area); + + interval = atoi (argv[0]); + + if (interval < ISIS_MIN_LSP_LIFETIME) { + vty_out (vty, "Level-2 LSP lifetime (%us) below %us%s", + interval, + ISIS_MIN_LSP_LIFETIME, + VTY_NEWLINE); + + return CMD_WARNING; + } + + + area->max_lsp_lifetime[1] = interval; + area->lsp_refresh[1] = interval - 300; + + return CMD_SUCCESS; +} + +DEFUN (no_lsp_lifetime_l2, + no_lsp_lifetime_l2_cmd, + "no lsp-lifetime level-2", + NO_STR + "LSP lifetime for Level 2 only in seconds\n" + ) +{ + struct isis_area *area; + + area = vty->index; + assert (area); + + area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */ + area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */ + + return CMD_SUCCESS; +} + +ALIAS (no_lsp_lifetime_l2, + no_lsp_lifetime_l2_arg_cmd, + "no lsp-lifetime level-2 <380-65535>", + NO_STR + "Maximum LSP lifetime for Level 2 only\n" + "LSP lifetime for Level 2 only in seconds\n" + ) + + + + +/* 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; + struct listnode *node2; + + LIST_LOOP (isis->area_list, area, node) { + /* 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; + LIST_LOOP (area->area_addrs, area_addr, node2) { + 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) { + vty_out (vty, " metric-style wide%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] != LSP_GEN_INTERVAL_DEFAULT) { + vty_out (vty, " lsp-gen-interval %d%s", area->lsp_gen_interval[0], + VTY_NEWLINE); + write ++; + }} else { + if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT) { + vty_out (vty, " lsp-gen-interval level-1 %d%s", + area->lsp_gen_interval[0], VTY_NEWLINE); + write ++; + } + if (area->lsp_gen_interval[1] != LSP_GEN_INTERVAL_DEFAULT) { + 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] != MAX_AGE) { + vty_out (vty, " lsp-lifetime %u%s", area->max_lsp_lifetime[0], + VTY_NEWLINE); + write ++; + }} else { + if (area->max_lsp_lifetime[0] != MAX_AGE) { + vty_out (vty, " lsp-lifetime level-1 %u%s", area->max_lsp_lifetime[0], + VTY_NEWLINE); + write ++; + } + if (area->max_lsp_lifetime[1] != MAX_AGE) { + vty_out (vty, " lsp-lifetime level-2 %u%s", area->max_lsp_lifetime[1], + VTY_NEWLINE); + write ++; + } + } + #ifdef TOPOLOGY_GENERATE + /* seems we save the whole command line here */ + if (area->top_params) { + vty_out (vty, " %s%s",area->top_params, VTY_NEWLINE); + write ++; + } + + if (memcmp(area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, + ISIS_SYS_ID_LEN)) { + vty_out (vty, " topology base_is %s%s", + sysid_print (area->topology_baseis), 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_clns_neighbors_cmd); + install_element (VIEW_NODE, &show_isis_neighbors_cmd); + install_element (VIEW_NODE, &show_clns_neighbors_detail_cmd); + install_element (VIEW_NODE, &show_isis_neighbors_detail_cmd); + + install_element (VIEW_NODE, &show_hostname_cmd); + install_element (VIEW_NODE, &show_database_cmd); + install_element (VIEW_NODE, &show_database_detail_cmd); + + install_element (ENABLE_NODE, &show_clns_neighbors_cmd); + install_element (ENABLE_NODE, &show_isis_neighbors_cmd); + install_element (ENABLE_NODE, &show_clns_neighbors_detail_cmd); + install_element (ENABLE_NODE, &show_isis_neighbors_detail_cmd); + + install_element (ENABLE_NODE, &show_hostname_cmd); + install_element (ENABLE_NODE, &show_database_cmd); + install_element (ENABLE_NODE, &show_database_detail_cmd); + install_element (ENABLE_NODE, &show_debugging_cmd); + + 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 (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_cmd); + install_element (ISIS_NODE, &no_area_passwd_cmd); + + install_element (ISIS_NODE, &domain_passwd_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, &lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_lsp_lifetime_cmd); + install_element (ISIS_NODE, &no_lsp_lifetime_arg_cmd); + install_element (ISIS_NODE, &lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_lsp_lifetime_l1_cmd); + install_element (ISIS_NODE, &no_lsp_lifetime_l1_arg_cmd); + install_element (ISIS_NODE, &lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_lsp_lifetime_l2_cmd); + install_element (ISIS_NODE, &no_lsp_lifetime_l2_arg_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); +#ifdef TOPOLOGY_GENERATE + install_element (ISIS_NODE, &topology_generate_grid_cmd); + install_element (ISIS_NODE, &topology_baseis_cmd); + install_element (ISIS_NODE, &no_topology_baseis_cmd); + install_element (VIEW_NODE, &show_isis_topology_cmd); + install_element (ENABLE_NODE, &show_isis_topology_cmd); +#endif /* TOPOLOGY_GENERATE */ + + isis_new(0); + isis_circuit_init (); + isis_zebra_init (); + isis_spf_cmds_init (); +} + + + + + + diff --git a/isisd/isisd.conf.sample b/isisd/isisd.conf.sample new file mode 100644 index 00000000..9e08778e --- /dev/null +++ b/isisd/isisd.conf.sample @@ -0,0 +1,39 @@ +! -*- 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 + +interface eth0 + ip router isis DEAD + ip address 10.101.43.194 + isis hello-interval 10000 +! 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 +! +! diff --git a/isisd/isisd.h b/isisd/isisd.h new file mode 100644 index 00000000..67bf8d63 --- /dev/null +++ b/isisd/isisd.h @@ -0,0 +1,147 @@ +/* + * 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" +#define ISIS_VTYSH_PATH "/tmp/.isisd" + +/* uncomment if you are a developer in bug hunt */ +/* #define EXTREME_DEBUG */ +/* #define EXTREME_TLV_DEBUG */ + +/* If you want topology stuff compiled in */ +/* #define TOPOLOGY_GENERATE */ + +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 */ + 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 */ + + /* 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 +}; + +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; /* IPv4 routes */ +#ifdef HAVE_IPV6 + struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v4 SPTs */ + struct route_table *route_table6; /* IPv6 routes */ +#endif + int min_bcast_mtu; + struct list *circuit_list; /* IS-IS circuits */ + struct flags flags; + struct thread *t_tick; /* LSP walker */ + struct thread *t_remove_aged; + int lsp_regenerate_pending[ISIS_LEVELS]; + struct thread *t_lsp_refresh[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; + /* 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 */ + 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; +#ifdef HAVE_IPV6 + int ipv6_circuits; +#endif /* HAVE_IPV6 */ + /* Counters */ + u_int32_t circuit_state_changes; +#ifdef TOPOLOGY_GENERATE + struct list *topology; + char topology_baseis[ISIS_SYS_ID_LEN]; /* is for the first is emulated */ + char top_params[200]; /* FIXME: what is reasonable? */ +#endif /* TOPOLOGY_GENERATE */ +}; + +void isis_init(void); +struct isis_area *isis_area_lookup (char *); + +#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) + +#endif /* ISISD_H */ diff --git a/isisd/iso_checksum.c b/isisd/iso_checksum.c new file mode 100644 index 00000000..d0bb8a75 --- /dev/null +++ b/isisd/iso_checksum.c @@ -0,0 +1,192 @@ +/* + * 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 <zebra.h> +#include "iso_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 + * FIXME: Check for overflow + */ + +int +iso_csum_verify (u_char *buffer, int len, uint16_t *csum) +{ + u_int8_t *p; + u_int32_t c0; + u_int32_t c1; + u_int16_t checksum; + int i; + + p = buffer; + checksum = 0; + 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; + + /* + * Otherwise initialize to zero and calculate... + */ + c0 = 0; + c1 = 0; + + for (i = 0; i < len; i++) { + c0 = c0 + *(p++); + c1 += c0; + } + + c0 = c0 % 255; + c1 = c1 % 255; + + if ( c0 == 0 && c1 == 0) + return 0; + + return 1; +} + + +/* + * Creates the checksum. *csum points to the position of the checksum in the + * PDU. + * Based on Annex C.4 of ISO/IEC 8473 + * we will not overflow until about length of 6000, + * which is the answer to (255+255n)*n/2 > 2^32 + * so if we have a length of over 5000 we will return zero (for now) + */ +#define FIXED_CODE +u_int16_t +iso_csum_create (u_char *buffer, int len, u_int16_t n) +{ + + u_int8_t *p; + int x; + int y; + u_int32_t mul; + u_int32_t c0; + u_int32_t c1; + u_int16_t checksum; + u_int16_t *csum; + int i; + + checksum = 0; + + /* + * Zero the csum in the packet. + */ + csum = (u_int16_t*)(buffer + n); + *(csum) = checksum; + + /* for the limitation of our implementation */ + if (len > 5000) { + return 0; + } + + p = buffer; + c0 = 0; + c1 = 0; + + for (i = 0; i < len; i++) { + c0 = c0 + *(p++); + c1 += c0; + } + + c0 = c0 % 255; + c1 = c1 % 255; + + mul = (len - n)*(c0); + +#ifdef FIXED_CODE + 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 = 255; + + x &= 0x00FF; + + checksum = ((y << 8) | x); + +#else + x = mul - c0 - c1; + x %= 255; + + y = c1 - mul - 1; + y %= 255; + + if (x == 0) x = 255; + if (y == 0) y = 255; + + checksum = ((y << 8) | x); +#endif + + /* + * Now we write this to the packet + */ + *(csum) = checksum; + + /* return the checksum for user usage */ + return checksum; +} + + +int +iso_csum_modify (u_char *buffer, int len, uint16_t *csum) +{ + + return 0; +} + + diff --git a/isisd/iso_checksum.h b/isisd/iso_checksum.h new file mode 100644 index 00000000..cf600a86 --- /dev/null +++ b/isisd/iso_checksum.h @@ -0,0 +1,29 @@ +/* + * 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); +u_int16_t iso_csum_create (u_char *buffer, int len, u_int16_t n); + +#endif /* _ZEBRA_ISO_CSUM_H */ diff --git a/isisd/modified/Makefile.am b/isisd/modified/Makefile.am new file mode 100644 index 00000000..65ba16bf --- /dev/null +++ b/isisd/modified/Makefile.am @@ -0,0 +1,17 @@ +## Process this file with automake to produce Makefile.in. + +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @ISISD@ \ + @VTYSH@ doc + +EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \ + vtysh/Makefile.am update-autotools + +dist-hook: + mkdir $(distdir)/tools + cp -p $(srcdir)/tools/*.pl $(distdir)/tools + cp -p $(srcdir)/tools/*.el $(distdir)/tools + cp -p $(srcdir)/tools/*.cgi $(distdir)/tools + mkdir $(distdir)/init + mkdir $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat diff --git a/isisd/modified/Makefile.in b/isisd/modified/Makefile.in new file mode 100644 index 00000000..6e136178 --- /dev/null +++ b/isisd/modified/Makefile.in @@ -0,0 +1,462 @@ +# Makefile.in generated by automake 1.6.2 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ +AR = @AR@ +AWK = @AWK@ +BGPD = @BGPD@ +CC = @CC@ +CPP = @CPP@ +CURSES = @CURSES@ +DEPDIR = @DEPDIR@ +IF_METHOD = @IF_METHOD@ +IF_PROC = @IF_PROC@ +INCLUDES = @INCLUDES@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPFORWARD = @IPFORWARD@ +ISISD = @ISISD@ +KERNEL_METHOD = @KERNEL_METHOD@ +LIBPAM = @LIBPAM@ +LIB_IPV6 = @LIB_IPV6@ +LIB_REGEX = @LIB_REGEX@ +MULTIPATH_NUM = @MULTIPATH_NUM@ +OSPF6D = @OSPF6D@ +OSPFD = @OSPFD@ +OTHER_METHOD = @OTHER_METHOD@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +RIPD = @RIPD@ +RIPNGD = @RIPNGD@ +RTREAD_METHOD = @RTREAD_METHOD@ +RT_METHOD = @RT_METHOD@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VTYSH = @VTYSH@ +ZEBRA = @ZEBRA@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ + +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @ISISD@ \ + @VTYSH@ doc + + +EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \ + vtysh/Makefile.am update-autotools + +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = + +RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ + uninstall-info-recursive all-recursive install-data-recursive \ + install-exec-recursive installdirs-recursive install-recursive \ + uninstall-recursive check-recursive installcheck-recursive +DIST_COMMON = README AUTHORS COPYING COPYING.LIB ChangeLog INSTALL \ + Makefile.am Makefile.in NEWS TODO acconfig.h aclocal.m4 \ + config.guess config.h.in config.sub configure configure.in \ + depcomp install-sh missing mkinstalldirs +DIST_SUBDIRS = $(SUBDIRS) +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: + +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) + +$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +$(ACLOCAL_M4): configure.in + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h + +$(srcdir)/config.h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + touch $(srcdir)/config.h.in + +distclean-hdr: + -rm -f config.h stamp-h1 +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = . +distdir = $(PACKAGE)-$(VERSION) + +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } + +GZIP_ENV = --best +distcleancheck_listfiles = find . -type f -print + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkinstalldirs) $(distdir)/vtysh + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="${top_distdir}" distdir="$(distdir)" \ + dist-hook + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + $(am__remove_distdir) + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/=inst && pwd` \ + && cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && (test `find $$dc_install_base -type f -print | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + find $$dc_install_base -type f -print ; \ + exit 1; } >&2 ) \ + && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ + && rm -f $(distdir).tar.gz \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @echo "$(distdir).tar.gz is ready for distribution" | \ + sed 'h;s/./=/g;p;x;p;x' +distcleancheck: distclean + if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf autom4te.cache +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \ + clean-generic clean-recursive dist dist-all dist-gzip distcheck \ + distclean distclean-generic distclean-hdr distclean-recursive \ + distclean-tags distcleancheck distdir dvi dvi-am dvi-recursive \ + info info-am info-recursive install install-am install-data \ + install-data-am install-data-recursive install-exec \ + install-exec-am install-exec-recursive install-info \ + install-info-am install-info-recursive install-man \ + install-recursive install-strip installcheck installcheck-am \ + installdirs installdirs-am installdirs-recursive \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-recursive tags tags-recursive uninstall \ + uninstall-am uninstall-info-am uninstall-info-recursive \ + uninstall-recursive + + +dist-hook: + mkdir $(distdir)/tools + cp -p $(srcdir)/tools/*.pl $(distdir)/tools + cp -p $(srcdir)/tools/*.el $(distdir)/tools + cp -p $(srcdir)/tools/*.cgi $(distdir)/tools + mkdir $(distdir)/init + mkdir $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat + cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/isisd/modified/README b/isisd/modified/README new file mode 100644 index 00000000..0b299532 --- /dev/null +++ b/isisd/modified/README @@ -0,0 +1,4 @@ +cp config.h.in acconfig.h configure.in Makefile.am Makefile.in configure ../../ +cp command.h command.c memory.c memory.h log.h log.c vty.c ../../lib/ +cp thread.h thread.c zebra.h ../../lib +cp rib.c ../../zebra/ diff --git a/isisd/modified/acconfig.h b/isisd/modified/acconfig.h new file mode 100644 index 00000000..002666ba --- /dev/null +++ b/isisd/modified/acconfig.h @@ -0,0 +1,162 @@ +/* accconfig.h -- `autoheader' will generate config.h.in for zebra. + Copyright (C) 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> */ + +/* Version of GNU Zebra */ +#undef VERSION + +/* Solaris on x86. */ +#undef SOLARIS_X86 + +/* Package name of GNU Zebra */ +#undef PACKAGE + +/* Define if host is GNU/Linux */ +#undef GNU_LINUX + +/* Define if you have the AF_ROUTE socket. */ +#undef HAVE_AF_ROUTE + +/* Define if you have the inet_aton function. */ +#undef HAVE_INET_ATON + +/* Define if you have the inet_ntop function. */ +#undef HAVE_INET_NTOP + +/* Define if you have the inet_pton function. */ +#undef HAVE_INET_PTON + +/* Define if you have the setproctitle function. */ +#undef HAVE_SETPROCTITLE + +/* Define if you have ipv6 stack. */ +#undef HAVE_IPV6 + +/* Define if you wish to support ipv6 router advertisment. */ +/* #undef HAVE_RTADV */ + +/* whether system has GNU regex */ +#undef HAVE_GNU_REGEX + +/* whether system has SNMP library */ +#undef HAVE_SNMP + +/* whether sockaddr has a sa_len field */ +#undef HAVE_SA_LEN + +/* whether sockaddr_in has a sin_len field */ +#undef HAVE_SIN_LEN + +/* whether sockaddr_un has a sun_len field */ +#undef HAVE_SUN_LEN + +/* whether sockaddr_in6 has a sin6_scope_id field */ +#undef HAVE_SIN6_SCOPE_ID + +/* Define if there is socklen_t. */ +#undef HAVE_SOCKLEN_T + +/* Define if there is sockaddr_dl structure. */ +#undef HAVE_SOCKADDR_DL + +/* Define if there is ifaliasreq structure. */ +#undef HAVE_IFALIASREQ + +/* Define if there is in6_aliasreq structure. */ +#undef HAVE_IN6_ALIASREQ + +/* Define if there is rt_addrinfo structure. */ +#undef HAVE_RT_ADDRINFO + +/* Define if there is in_pktinfo structure. */ +#undef HAVE_INPKTINFO + +/* Define if you have the getrusage function. */ +#undef HAVE_RUSAGE + +/* Define if /proc/net/dev exists. */ +#undef HAVE_PROC_NET_DEV + +/* Define if /proc/net/if_inet6 exists. */ +#undef HAVE_PROC_NET_IF_INET6 + +/* Define if NET_RT_IFLIST exists in sys/socket.h. */ +#undef HAVE_NET_RT_IFLIST + +/* Define if you have INRIA ipv6 stack. */ +#undef INRIA_IPV6 + +/* Define if you have KAME project ipv6 stack. */ +#undef KAME + +/* Define if you have Linux ipv6 stack. */ +#undef LINUX_IPV6 + +/* Define if you have NRL ipv6 stack. */ +#undef NRL + +/* Define if you have BSDI NRL IPv6 stack. */ +#undef BSDI_NRL + +/* Define if one-vty option is specified. */ +#undef VTYSH + +/* Define if interface aliases don't have distinct indeces */ +#undef HAVE_BROKEN_ALIASES + +/* Define if disable-bgp-announce option is specified. */ +#undef DISABLE_BGP_ANNOUNCE + +/* PAM support */ +#undef USE_PAM + +/* TCP/IP communication between zebra and protocol daemon. */ +#undef HAVE_TCP_ZEBRA + +/* The OSPF NSSA option (RFC1587). */ +#undef HAVE_NSSA + +/* The OSPF Opaque LSA option (RFC2370). */ +#undef HAVE_OPAQUE_LSA + +/* Traffic Engineering Extension to OSPF + (draft-katz-yeung-ospf-traffic-06.txt). */ +#undef HAVE_OSPF_TE + +/* Linux netlink. */ +#undef HAVE_NETLINK + +/* PATHS */ +#undef PATH_ZEBRA_PID +#undef PATH_RIPD_PID +#undef PATH_RIPNGD_PID +#undef PATH_BGPD_PID +#undef PATH_OSPFD_PID +#undef PATH_OSPF6D_PID +#undef PATH_ISISD_PID + +/* Define if Solaris */ +#undef SUNOS_5 + +/* Define if FreeBSD 3.2 */ +#undef FREEBSD_32 + +/* Define if OpenBSD */ +#undef OPEN_BSD + +#ifdef HAVE_IPV6 +#ifdef KAME +#ifndef INET6 +#define INET6 +#endif /* INET6 */ +#endif /* KAME */ +#endif /* HAVE_IPV6 */ + +#ifdef SUNOS_5 +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned short u_int8_t; +#endif /* SUNOS_5 */ + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif /* HAVE_SOCKLEN_T */ diff --git a/isisd/modified/command.c b/isisd/modified/command.c new file mode 100644 index 00000000..5c18fd94 --- /dev/null +++ b/isisd/modified/command.c @@ -0,0 +1,2983 @@ +/* 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 <zebra.h> + +#include "command.h" +#include "memory.h" +#include "log.h" +#include "version.h" + +/* Command vector which includes some level of command lists. Normally + each daemon maintains each own cmdvec. */ +vector cmdvec; + +/* Host information structure. */ +struct host host; + +/* Default motd string. */ +char *default_motd = +"\r\n\ +Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\ +Copyright 1996-2002 Kunihiro Ishiguro.\r\n\ +\r\n"; + +/* Standard command node structures. */ +struct cmd_node auth_node = +{ + AUTH_NODE, + "Password: ", +}; + +struct cmd_node view_node = +{ + VIEW_NODE, + "%s> ", +}; + +struct cmd_node auth_enable_node = +{ + AUTH_ENABLE_NODE, + "Password: ", +}; + +struct cmd_node enable_node = +{ + ENABLE_NODE, + "%s# ", +}; + +struct cmd_node config_node = +{ + CONFIG_NODE, + "%s(config)# ", + 1 +}; + +/* Utility function to concatenate argv argument into a single string + with inserting ' ' character between each argument. */ +char * +argv_concat (char **argv, int argc, int shift) +{ + int i; + int len; + int index; + char *str; + + str = NULL; + index = 0; + + for (i = shift; i < argc; i++) + { + len = strlen (argv[i]); + + if (i == shift) + { + str = XSTRDUP (MTYPE_TMP, argv[i]); + index = len; + } + else + { + str = XREALLOC (MTYPE_TMP, str, (index + len + 2)); + str[index++] = ' '; + memcpy (str + index, argv[i], len); + index += len; + str[index] = '\0'; + } + } + return str; +} + +/* Install top node of command vector. */ +void +install_node (struct cmd_node *node, + int (*func) (struct vty *)) +{ + vector_set_index (cmdvec, node->node, node); + node->func = func; + node->cmd_vector = vector_init (VECTOR_MIN_SIZE); +} + +/* Compare two command's string. Used in sort_node (). */ +int +cmp_node (const void *p, const void *q) +{ + struct cmd_element *a = *(struct cmd_element **)p; + struct cmd_element *b = *(struct cmd_element **)q; + + return strcmp (a->string, b->string); +} + +int +cmp_desc (const void *p, const void *q) +{ + struct desc *a = *(struct desc **)p; + struct desc *b = *(struct desc **)q; + + return strcmp (a->cmd, b->cmd); +} + +/* Sort each node's command element according to command string. */ +void +sort_node () +{ + int i, j; + struct cmd_node *cnode; + vector descvec; + struct cmd_element *cmd_element; + + for (i = 0; i < vector_max (cmdvec); i++) + if ((cnode = vector_slot (cmdvec, i)) != NULL) + { + vector cmd_vector = cnode->cmd_vector; + qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node); + + for (j = 0; j < vector_max (cmd_vector); j++) + if ((cmd_element = vector_slot (cmd_vector, j)) != NULL) + { + descvec = vector_slot (cmd_element->strvec, + vector_max (cmd_element->strvec) - 1); + qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc); + } + } +} + +/* Breaking up string into each command piece. I assume given + character is separated by a space character. Return value is a + vector which includes char ** data element. */ +vector +cmd_make_strvec (char *string) +{ + char *cp, *start, *token; + int strlen; + vector strvec; + + if (string == NULL) + return NULL; + + cp = string; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + if (*cp == '!' || *cp == '#') + return NULL; + + /* Prepare return vector. */ + strvec = vector_init (VECTOR_MIN_SIZE); + + /* Copy each command piece and set into vector. */ + while (1) + { + start = cp; + while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') && + *cp != '\0') + cp++; + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + vector_set (strvec, token); + + while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') && + *cp != '\0') + cp++; + + if (*cp == '\0') + return strvec; + } +} + +/* Free allocated string vector. */ +void +cmd_free_strvec (vector v) +{ + int i; + char *cp; + + if (!v) + return; + + for (i = 0; i < vector_max (v); i++) + if ((cp = vector_slot (v, i)) != NULL) + XFREE (MTYPE_STRVEC, cp); + + vector_free (v); +} + +/* Fetch next description. Used in cmd_make_descvec(). */ +char * +cmd_desc_str (char **string) +{ + char *cp, *start, *token; + int strlen; + + cp = *string; + + if (cp == NULL) + return NULL; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + start = cp; + + while (!(*cp == '\r' || *cp == '\n') && *cp != '\0') + cp++; + + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + + *string = cp; + + return token; +} + +/* New string vector. */ +vector +cmd_make_descvec (char *string, char *descstr) +{ + int multiple = 0; + char *sp; + char *token; + int len; + char *cp; + char *dp; + vector allvec; + vector strvec = NULL; + struct desc *desc; + + cp = string; + dp = descstr; + + if (cp == NULL) + return NULL; + + allvec = vector_init (VECTOR_MIN_SIZE); + + while (1) + { + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + if (*cp == '(') + { + multiple = 1; + cp++; + } + if (*cp == ')') + { + multiple = 0; + cp++; + } + if (*cp == '|') + { + if (! multiple) + { + fprintf (stderr, "Command parse error!: %s\n", string); + exit (1); + } + cp++; + } + + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + if (*cp == '(') + { + multiple = 1; + cp++; + } + + if (*cp == '\0') + return allvec; + + sp = cp; + + while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0') + cp++; + + len = cp - sp; + + token = XMALLOC (MTYPE_STRVEC, len + 1); + memcpy (token, sp, len); + *(token + len) = '\0'; + + desc = XCALLOC (MTYPE_DESC, sizeof (struct desc)); + desc->cmd = token; + desc->str = cmd_desc_str (&dp); + + if (multiple) + { + if (multiple == 1) + { + strvec = vector_init (VECTOR_MIN_SIZE); + vector_set (allvec, strvec); + } + multiple++; + } + else + { + strvec = vector_init (VECTOR_MIN_SIZE); + vector_set (allvec, strvec); + } + vector_set (strvec, desc); + } +} + +/* Count mandantory string vector size. This is to determine inputed + command has enough command length. */ +int +cmd_cmdsize (vector strvec) +{ + int i; + char *str; + int size = 0; + vector descvec; + + for (i = 0; i < vector_max (strvec); i++) + { + descvec = vector_slot (strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + + str = desc->cmd; + + if (str == NULL || CMD_OPTION (str)) + return size; + else + size++; + } + else + size++; + } + return size; +} + +/* Return prompt character of specified node. */ +char * +cmd_prompt (enum node_type node) +{ + struct cmd_node *cnode; + + cnode = vector_slot (cmdvec, node); + return cnode->prompt; +} + +/* Install a command into a node. */ +void +install_element (enum node_type ntype, struct cmd_element *cmd) +{ + struct cmd_node *cnode; + + cnode = vector_slot (cmdvec, ntype); + + if (cnode == NULL) + { + fprintf (stderr, "Command node %d doesn't exist, please check it\n", + ntype); + exit (1); + } + + vector_set (cnode->cmd_vector, cmd); + + cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc); + cmd->cmdsize = cmd_cmdsize (cmd->strvec); +} + +static unsigned char itoa64[] = +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void +to64(char *s, long v, int n) +{ + while (--n >= 0) + { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +char *zencrypt (char *passwd) +{ + char salt[6]; + struct timeval tv; + char *crypt (const char *, const char *); + + gettimeofday(&tv,0); + + to64(&salt[0], random(), 3); + to64(&salt[3], tv.tv_usec, 3); + salt[5] = '\0'; + + return crypt (passwd, salt); +} + +/* This function write configuration of this host. */ +int +config_write_host (struct vty *vty) +{ + if (host.name) + vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE); + + if (host.encrypt) + { + if (host.password_encrypt) + vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); + if (host.enable_encrypt) + vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); + } + else + { + if (host.password) + vty_out (vty, "password %s%s", host.password, VTY_NEWLINE); + if (host.enable) + vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE); + } + + if (host.logfile) + vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE); + + if (host.log_stdout) + vty_out (vty, "log stdout%s", VTY_NEWLINE); + + if (host.log_syslog) + vty_out (vty, "log syslog%s", VTY_NEWLINE); + + if (zlog_default->maskpri != LOG_DEBUG) + vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE); + + if (zlog_default->record_priority == 1) + vty_out (vty, "log record-priority%s", VTY_NEWLINE); + + if (host.advanced) + vty_out (vty, "service advanced-vty%s", VTY_NEWLINE); + + if (host.encrypt) + vty_out (vty, "service password-encryption%s", VTY_NEWLINE); + + if (host.lines >= 0) + vty_out (vty, "service terminal-length %d%s", host.lines, + VTY_NEWLINE); + + if (! host.motd) + vty_out (vty, "no banner motd%s", VTY_NEWLINE); + + return 1; +} + +/* Utility function for getting command vector. */ +vector +cmd_node_vector (vector v, enum node_type ntype) +{ + struct cmd_node *cnode = vector_slot (v, ntype); + return cnode->cmd_vector; +} + +/* Filter command vector by symbol */ +int +cmd_filter_by_symbol (char *command, char *symbol) +{ + int i, lim; + + if (strcmp (symbol, "IPV4_ADDRESS") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/')) + return 1; + i++; + } + return 0; + } + if (strcmp (symbol, "STRING") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-')) + return 1; + i++; + } + return 0; + } + if (strcmp (symbol, "IFNAME") == 0) + { + i = 0; + lim = strlen (command); + while (i < lim) + { + if (! isalnum ((int) command[i])) + return 1; + i++; + } + return 0; + } + return 0; +} + +/* Completion match types. */ +enum match_type +{ + no_match, + extend_match, + ipv4_prefix_match, + ipv4_match, + ipv6_prefix_match, + ipv6_match, + range_match, + vararg_match, + partly_match, + exact_match +}; + +enum match_type +cmd_ipv4_match (char *str) +{ + char *sp; + int dots = 0, nums = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) + { + memset (buf, 0, sizeof (buf)); + sp = str; + while (*str != '\0') + { + if (*str == '.') + { + if (dots >= 3) + return no_match; + + if (*(str + 1) == '.') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy (buf, sp, str - sp); + if (atoi (buf) > 255) + return no_match; + + nums++; + + if (*str == '\0') + break; + + str++; + } + + if (nums < 4) + return partly_match; + + return exact_match; +} + +enum match_type +cmd_ipv4_prefix_match (char *str) +{ + char *sp; + int dots = 0; + char buf[4]; + + if (str == NULL) + return partly_match; + + for (;;) + { + memset (buf, 0, sizeof (buf)); + sp = str; + while (*str != '\0' && *str != '/') + { + if (*str == '.') + { + if (dots == 3) + return no_match; + + if (*(str + 1) == '.' || *(str + 1) == '/') + return no_match; + + if (*(str + 1) == '\0') + return partly_match; + + dots++; + break; + } + + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (str - sp > 3) + return no_match; + + strncpy (buf, sp, str - sp); + if (atoi (buf) > 255) + return no_match; + + if (dots == 3) + { + if (*str == '/') + { + if (*(str + 1) == '\0') + return partly_match; + + str++; + break; + } + else if (*str == '\0') + return partly_match; + } + + if (*str == '\0') + return partly_match; + + str++; + } + + sp = str; + while (*str != '\0') + { + if (!isdigit ((int) *str)) + return no_match; + + str++; + } + + if (atoi (sp) > 32) + return no_match; + + return exact_match; +} + +#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%" +#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/" +#define STATE_START 1 +#define STATE_COLON 2 +#define STATE_DOUBLE 3 +#define STATE_ADDR 4 +#define STATE_DOT 5 +#define STATE_SLASH 6 +#define STATE_MASK 7 + +enum match_type +cmd_ipv6_match (char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + char *sp = NULL; + + if (str == NULL) + return partly_match; + + if (strspn (str, IPV6_ADDR_STR) != strlen (str)) + return no_match; + + while (*str != '\0') + { + switch (state) + { + case STATE_START: + if (*str == ':') + { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } + else + { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == ':') + state = STATE_DOUBLE; + else + { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else + { + if (*(str + 1) != '\0') + colons++; + sp = str + 1; + state = STATE_ADDR; + } + + double_colon++; + nums++; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '\0') + { + if (str - sp > 3) + return no_match; + + nums++; + state = STATE_COLON; + } + if (*(str + 1) == '.') + state = STATE_DOT; + break; + case STATE_DOT: + state = STATE_ADDR; + break; + default: + break; + } + + if (nums > 8) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + +#if 0 + if (nums < 11) + return partly_match; +#endif /* 0 */ + + return exact_match; +} + +enum match_type +cmd_ipv6_prefix_match (char *str) +{ + int state = STATE_START; + int colons = 0, nums = 0, double_colon = 0; + int mask; + char *sp = NULL; + char *endptr = NULL; + + if (str == NULL) + return partly_match; + + if (strspn (str, IPV6_PREFIX_STR) != strlen (str)) + return no_match; + + while (*str != '\0' && state != STATE_MASK) + { + switch (state) + { + case STATE_START: + if (*str == ':') + { + if (*(str + 1) != ':' && *(str + 1) != '\0') + return no_match; + colons--; + state = STATE_COLON; + } + else + { + sp = str; + state = STATE_ADDR; + } + + continue; + case STATE_COLON: + colons++; + if (*(str + 1) == '/') + return no_match; + else if (*(str + 1) == ':') + state = STATE_DOUBLE; + else + { + sp = str + 1; + state = STATE_ADDR; + } + break; + case STATE_DOUBLE: + if (double_colon) + return no_match; + + if (*(str + 1) == ':') + return no_match; + else + { + if (*(str + 1) != '\0' && *(str + 1) != '/') + colons++; + sp = str + 1; + + if (*(str + 1) == '/') + state = STATE_SLASH; + else + state = STATE_ADDR; + } + + double_colon++; + nums += 1; + break; + case STATE_ADDR: + if (*(str + 1) == ':' || *(str + 1) == '.' + || *(str + 1) == '\0' || *(str + 1) == '/') + { + if (str - sp > 3) + return no_match; + + for (; sp <= str; sp++) + if (*sp == '/') + return no_match; + + nums++; + + if (*(str + 1) == ':') + state = STATE_COLON; + else if (*(str + 1) == '.') + state = STATE_DOT; + else if (*(str + 1) == '/') + state = STATE_SLASH; + } + break; + case STATE_DOT: + state = STATE_ADDR; + break; + case STATE_SLASH: + if (*(str + 1) == '\0') + return partly_match; + + state = STATE_MASK; + break; + default: + break; + } + + if (nums > 11) + return no_match; + + if (colons > 7) + return no_match; + + str++; + } + + if (state < STATE_MASK) + return partly_match; + + mask = strtol (str, &endptr, 10); + if (*endptr != '\0') + return no_match; + + if (mask < 0 || mask > 128) + return no_match; + +/* I don't know why mask < 13 makes command match partly. + Forgive me to make this comments. I Want to set static default route + because of lack of function to originate default in ospf6d; sorry + yasu + if (mask < 13) + return partly_match; +*/ + + return exact_match; +} + +#define DECIMAL_STRLEN_MAX 10 + +int +cmd_range_match (char *range, char *str) +{ + char *p; + char buf[DECIMAL_STRLEN_MAX + 1]; + char *endptr = NULL; + unsigned long min, max, val; + + if (str == NULL) + return 1; + + val = strtoul (str, &endptr, 10); + if (*endptr != '\0') + return 0; + + range++; + p = strchr (range, '-'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy (buf, range, p - range); + buf[p - range] = '\0'; + min = strtoul (buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + range = p + 1; + p = strchr (range, '>'); + if (p == NULL) + return 0; + if (p - range > DECIMAL_STRLEN_MAX) + return 0; + strncpy (buf, range, p - range); + buf[p - range] = '\0'; + max = strtoul (buf, &endptr, 10); + if (*endptr != '\0') + return 0; + + if (val < min || val > max) + return 0; + + return 1; +} + +/* Make completion match and return match type flag. */ +enum match_type +cmd_filter_by_completion (char *command, vector v, int index) +{ + int i; + char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + if (index >= vector_max (cmd_element->strvec)) + vector_slot (v, i) = NULL; + else + { + int j; + int matched = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + str = desc->cmd; + + if (CMD_VARARG (str)) + { + if (match_type < vararg_match) + match_type = vararg_match; + matched++; + } + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + { + if (match_type < range_match) + match_type = range_match; + + matched++; + } + } + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command)) + { + if (match_type < ipv6_match) + match_type = ipv6_match; + + matched++; + } + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command)) + { + if (match_type < ipv6_prefix_match) + match_type = ipv6_prefix_match; + + matched++; + } + } + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command)) + { + if (match_type < ipv4_match) + match_type = ipv4_match; + + matched++; + } + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command)) + { + if (match_type < ipv4_prefix_match) + match_type = ipv4_prefix_match; + matched++; + } + } + else + /* Check is this point's argument optional ? */ + if (CMD_OPTION (str) || CMD_VARIABLE (str)) + { + if (match_type < extend_match) + match_type = extend_match; + matched++; + } + else if (strncmp (command, str, strlen (command)) == 0) + { + if (strcmp (command, str) == 0) + match_type = exact_match; + else + { + if (match_type < partly_match) + match_type = partly_match; + } + matched++; + } + } + if (! matched) + vector_slot (v, i) = NULL; + } + } + return match_type; +} + +/* Filter vector by command character with index. */ +enum match_type +cmd_filter_by_string (char *command, vector v, int index) +{ + int i; + char *str; + struct cmd_element *cmd_element; + enum match_type match_type; + vector descvec; + struct desc *desc; + + match_type = no_match; + + /* If command and cmd_element string does not match set NULL to vector */ + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + /* If given index is bigger than max string vector of command, + set NULL*/ + if (index >= vector_max (cmd_element->strvec)) + vector_slot (v, i) = NULL; + else + { + int j; + int matched = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + str = desc->cmd; + + if (CMD_VARARG (str)) + { + if (match_type < vararg_match) + match_type = vararg_match; + matched++; + } + else if (CMD_RANGE (str)) + { + if (cmd_range_match (str, command)) + { + if (match_type < range_match) + match_type = range_match; + matched++; + } + } + else if (CMD_IPV6 (str)) + { + if (cmd_ipv6_match (command) == exact_match) + { + if (match_type < ipv6_match) + match_type = ipv6_match; + matched++; + } + } + else if (CMD_IPV6_PREFIX (str)) + { + if (cmd_ipv6_prefix_match (command) == exact_match) + { + if (match_type < ipv6_prefix_match) + match_type = ipv6_prefix_match; + matched++; + } + } + else if (CMD_IPV4 (str)) + { + if (cmd_ipv4_match (command) == exact_match) + { + if (match_type < ipv4_match) + match_type = ipv4_match; + matched++; + } + } + else if (CMD_IPV4_PREFIX (str)) + { + if (cmd_ipv4_prefix_match (command) == exact_match) + { + if (match_type < ipv4_prefix_match) + match_type = ipv4_prefix_match; + matched++; + } + } + else if (CMD_OPTION (str) || CMD_VARIABLE (str)) + { + if (match_type < extend_match) + match_type = extend_match; + matched++; + } + else + { + if (strcmp (command, str) == 0) + { + match_type = exact_match; + matched++; + } + } + } + if (! matched) + vector_slot (v, i) = NULL; + } + } + return match_type; +} + +/* Check ambiguous match */ +int +is_cmd_ambiguous (char *command, vector v, int index, enum match_type type) +{ + int i; + int j; + char *str = NULL; + struct cmd_element *cmd_element; + char *matched = NULL; + vector descvec; + struct desc *desc; + + for (i = 0; i < vector_max (v); i++) + if ((cmd_element = vector_slot (v, i)) != NULL) + { + int match = 0; + + descvec = vector_slot (cmd_element->strvec, index); + + for (j = 0; j < vector_max (descvec); j++) + { + enum match_type ret; + + desc = vector_slot (descvec, j); + str = desc->cmd; + + switch (type) + { + case exact_match: + if (! (CMD_OPTION (str) || CMD_VARIABLE (str)) + && strcmp (command, str) == 0) + match++; + break; + case partly_match: + if (! (CMD_OPTION (str) || CMD_VARIABLE (str)) + && strncmp (command, str, strlen (command)) == 0) + { + if (matched && strcmp (matched, str) != 0) + return 1; /* There is ambiguous match. */ + else + matched = str; + match++; + } + break; + case range_match: + if (cmd_range_match (str, command)) + { + if (matched && strcmp (matched, str) != 0) + return 1; + else + matched = str; + match++; + } + break; + case ipv6_match: + if (CMD_IPV6 (str)) + match++; + break; + case ipv6_prefix_match: + if ((ret = cmd_ipv6_prefix_match (command)) != no_match) + { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case ipv4_match: + if (CMD_IPV4 (str)) + match++; + break; + case ipv4_prefix_match: + if ((ret = cmd_ipv4_prefix_match (command)) != no_match) + { + if (ret == partly_match) + return 2; /* There is incomplete match. */ + + match++; + } + break; + case extend_match: + if (CMD_OPTION (str) || CMD_VARIABLE (str)) + match++; + break; + case no_match: + default: + break; + } + } + if (! match) + vector_slot (v, i) = NULL; + } + return 0; +} + +/* If src matches dst return dst string, otherwise return NULL */ +char * +cmd_entry_function (char *src, char *dst) +{ + /* Skip variable arguments. */ + if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) || + CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst)) + return NULL; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + /* Matched with input string. */ + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + + return NULL; +} + +/* If src matches dst return dst string, otherwise return NULL */ +/* This version will return the dst string always if it is + CMD_VARIABLE for '?' key processing */ +char * +cmd_entry_function_desc (char *src, char *dst) +{ + if (CMD_VARARG (dst)) + return dst; + + if (CMD_RANGE (dst)) + { + if (cmd_range_match (dst, src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6 (dst)) + { + if (cmd_ipv6_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV6_PREFIX (dst)) + { + if (cmd_ipv6_prefix_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4 (dst)) + { + if (cmd_ipv4_match (src)) + return dst; + else + return NULL; + } + + if (CMD_IPV4_PREFIX (dst)) + { + if (cmd_ipv4_prefix_match (src)) + return dst; + else + return NULL; + } + + /* Optional or variable commands always match on '?' */ + if (CMD_OPTION (dst) || CMD_VARIABLE (dst)) + return dst; + + /* In case of 'command \t', given src is NULL string. */ + if (src == NULL) + return dst; + + if (strncmp (src, dst, strlen (src)) == 0) + return dst; + else + return NULL; +} + +/* Check same string element existence. If it isn't there return + 1. */ +int +cmd_unique_string (vector v, char *str) +{ + int i; + char *match; + + for (i = 0; i < vector_max (v); i++) + if ((match = vector_slot (v, i)) != NULL) + if (strcmp (match, str) == 0) + return 0; + return 1; +} + +/* Compare string to description vector. If there is same string + return 1 else return 0. */ +int +desc_unique_string (vector v, char *str) +{ + int i; + struct desc *desc; + + for (i = 0; i < vector_max (v); i++) + if ((desc = vector_slot (v, i)) != NULL) + if (strcmp (desc->cmd, str) == 0) + return 1; + return 0; +} + +/* '?' describe command support. */ +vector +cmd_describe_command (vector vline, struct vty *vty, int *status) +{ + int i; + vector cmd_vector; +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + int index; + static struct desc desc_cr = { "<cr>", "" }; + + /* Set index. */ + index = vector_max (vline) - 1; + + /* Make copy vector of current node's command vector. */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + /* Prepare match vector */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + + /* Filter commands. */ + for (i = 0; i < index; i++) + { + enum match_type match; + char *command; + int ret; + + command = vector_slot (vline, i); + + match = cmd_filter_by_completion (command, cmd_vector, i); + + if (match == vararg_match) + { + struct cmd_element *cmd_element; + vector descvec; + int j, k; + + for (j = 0; j < vector_max (cmd_vector); j++) + if ((cmd_element = vector_slot (cmd_vector, j)) != NULL) + { + descvec = vector_slot (cmd_element->strvec, + vector_max (cmd_element->strvec) - 1); + for (k = 0; k < vector_max (descvec); k++) + { + struct desc *desc = vector_slot (descvec, k); + vector_set (matchvec, desc); + } + } + + vector_set (matchvec, &desc_cr); + + vector_free (cmd_vector); + + return matchvec; + } + + if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) + { + vector_free (cmd_vector); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + else if (ret == 2) + { + vector_free (cmd_vector); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + } + + /* Prepare match vector */ + /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */ + + /* Make description vector. */ + for (i = 0; i < vector_max (cmd_vector); i++) + if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) + { + char *string = NULL; + vector strvec = cmd_element->strvec; + + if (index > vector_max (strvec)) + vector_slot (cmd_vector, i) = NULL; + else + { + /* Check is command is completed. */ + if (index == vector_max (strvec)) + { + string = "<cr>"; + if (! desc_unique_string (matchvec, string)) + vector_set (matchvec, &desc_cr); + } + else + { + int j; + vector descvec = vector_slot (strvec, index); + struct desc *desc; + + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd); + if (string) + { + /* Uniqueness check */ + if (! desc_unique_string (matchvec, string)) + vector_set (matchvec, desc); + } + } + } + } + } + vector_free (cmd_vector); + + if (vector_slot (matchvec, 0) == NULL) + { + vector_free (matchvec); + *status= CMD_ERR_NO_MATCH; + } + else + *status = CMD_SUCCESS; + + return matchvec; +} + +/* Check LCD of matched command. */ +int +cmd_lcd (char **matched) +{ + int i; + int j; + int lcd = -1; + char *s1, *s2; + char c1, c2; + + if (matched[0] == NULL || matched[1] == NULL) + return 0; + + for (i = 1; matched[i] != NULL; i++) + { + s1 = matched[i - 1]; + s2 = matched[i]; + + for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++) + if (c1 != c2) + break; + + if (lcd < 0) + lcd = j; + else + { + if (lcd > j) + lcd = j; + } + } + return lcd; +} + +/* Command line completion support. */ +char ** +cmd_complete_command (vector vline, struct vty *vty, int *status) +{ + int i; + vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); +#define INIT_MATCHVEC_SIZE 10 + vector matchvec; + struct cmd_element *cmd_element; + int index = vector_max (vline) - 1; + char **match_str; + struct desc *desc; + vector descvec; + char *command; + int lcd; + + /* First, filter by preceeding command string */ + for (i = 0; i < index; i++) + { + enum match_type match; + int ret; + + command = vector_slot (vline, i); + + /* First try completion match, if there is exactly match return 1 */ + match = cmd_filter_by_completion (command, cmd_vector, i); + + /* If there is exact match then filter ambiguous match else check + ambiguousness. */ + if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1) + { + vector_free (cmd_vector); + *status = CMD_ERR_AMBIGUOUS; + return NULL; + } + /* + else if (ret == 2) + { + vector_free (cmd_vector); + *status = CMD_ERR_NO_MATCH; + return NULL; + } + */ + } + + /* Prepare match vector. */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + + /* Now we got into completion */ + for (i = 0; i < vector_max (cmd_vector); i++) + if ((cmd_element = vector_slot (cmd_vector, i)) != NULL) + { + char *string; + vector strvec = cmd_element->strvec; + + /* Check field length */ + if (index >= vector_max (strvec)) + vector_slot (cmd_vector, i) = NULL; + else + { + int j; + + descvec = vector_slot (strvec, index); + for (j = 0; j < vector_max (descvec); j++) + { + desc = vector_slot (descvec, j); + + if ((string = cmd_entry_function (vector_slot (vline, index), + desc->cmd))) + if (cmd_unique_string (matchvec, string)) + vector_set (matchvec, XSTRDUP (MTYPE_TMP, string)); + } + } + } + + /* We don't need cmd_vector any more. */ + vector_free (cmd_vector); + + /* No matched command */ + if (vector_slot (matchvec, 0) == NULL) + { + vector_free (matchvec); + + /* In case of 'command \t' pattern. Do you need '?' command at + the end of the line. */ + if (vector_slot (vline, index) == '\0') + *status = CMD_ERR_NOTHING_TODO; + else + *status = CMD_ERR_NO_MATCH; + return NULL; + } + + /* Only one matched */ + if (vector_slot (matchvec, 1) == NULL) + { + match_str = (char **) matchvec->index; + vector_only_wrapper_free (matchvec); + *status = CMD_COMPLETE_FULL_MATCH; + return match_str; + } + /* Make it sure last element is NULL. */ + vector_set (matchvec, NULL); + + /* Check LCD of matched strings. */ + if (vector_slot (vline, index) != NULL) + { + lcd = cmd_lcd ((char **) matchvec->index); + + if (lcd) + { + int len = strlen (vector_slot (vline, index)); + + if (len < lcd) + { + char *lcdstr; + + lcdstr = XMALLOC (MTYPE_TMP, lcd + 1); + memcpy (lcdstr, matchvec->index[0], lcd); + lcdstr[lcd] = '\0'; + + /* match_str = (char **) &lcdstr; */ + + /* Free matchvec. */ + for (i = 0; i < vector_max (matchvec); i++) + { + if (vector_slot (matchvec, i)) + XFREE (MTYPE_TMP, vector_slot (matchvec, i)); + } + vector_free (matchvec); + + /* Make new matchvec. */ + matchvec = vector_init (INIT_MATCHVEC_SIZE); + vector_set (matchvec, lcdstr); + match_str = (char **) matchvec->index; + vector_only_wrapper_free (matchvec); + + *status = CMD_COMPLETE_MATCH; + return match_str; + } + } + } + + match_str = (char **) matchvec->index; + vector_only_wrapper_free (matchvec); + *status = CMD_COMPLETE_LIST_MATCH; + return match_str; +} + +/* Execute command by argument vline vector. */ +int +cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) +{ + int i; + int index; + vector cmd_vector; + struct cmd_element *cmd_element; + struct cmd_element *matched_element; + unsigned int matched_count, incomplete_count; + int argc; + char *argv[CMD_ARGC_MAX]; + enum match_type match = 0; + int varflag; + char *command; + + /* Make copy of command elements. */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + for (index = 0; index < vector_max (vline); index++) + { + int ret; + + command = vector_slot (vline, index); + + match = cmd_filter_by_completion (command, cmd_vector, index); + + if (match == vararg_match) + break; + + ret = is_cmd_ambiguous (command, cmd_vector, index, match); + + if (ret == 1) + { + vector_free (cmd_vector); + return CMD_ERR_AMBIGUOUS; + } + else if (ret == 2) + { + vector_free (cmd_vector); + return CMD_ERR_NO_MATCH; + } + } + + /* Check matched count. */ + matched_element = NULL; + matched_count = 0; + incomplete_count = 0; + + for (i = 0; i < vector_max (cmd_vector); i++) + if (vector_slot (cmd_vector,i) != NULL) + { + cmd_element = vector_slot (cmd_vector,i); + + if (match == vararg_match || index >= cmd_element->cmdsize) + { + matched_element = cmd_element; +#if 0 + printf ("DEBUG: %s\n", cmd_element->string); +#endif + matched_count++; + } + else + { + incomplete_count++; + } + } + + /* Finish of using cmd_vector. */ + vector_free (cmd_vector); + + /* To execute command, matched_count must be 1.*/ + if (matched_count == 0) + { + if (incomplete_count) + return CMD_ERR_INCOMPLETE; + else + return CMD_ERR_NO_MATCH; + } + + if (matched_count > 1) + return CMD_ERR_AMBIGUOUS; + + /* Argument treatment */ + varflag = 0; + argc = 0; + + for (i = 0; i < vector_max (vline); i++) + { + if (varflag) + argv[argc++] = vector_slot (vline, i); + else + { + vector descvec = vector_slot (matched_element->strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + char *str = desc->cmd; + + if (CMD_VARARG (str)) + varflag = 1; + + if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str)) + argv[argc++] = vector_slot (vline, i); + } + else + argv[argc++] = vector_slot (vline, i); + } + + if (argc >= CMD_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + + /* For vtysh execution. */ + if (cmd) + *cmd = matched_element; + + if (matched_element->daemon) + return CMD_SUCCESS_DAEMON; + + /* Execute matched command. */ + return (*matched_element->func) (matched_element, vty, argc, argv); +} + +/* Execute command by argument readline. */ +int +cmd_execute_command_strict (vector vline, struct vty *vty, + struct cmd_element **cmd) +{ + int i; + int index; + vector cmd_vector; + struct cmd_element *cmd_element; + struct cmd_element *matched_element; + unsigned int matched_count, incomplete_count; + int argc; + char *argv[CMD_ARGC_MAX]; + int varflag; + enum match_type match = 0; + char *command; + + /* Make copy of command element */ + cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node)); + + for (index = 0; index < vector_max (vline); index++) + { + int ret; + + command = vector_slot (vline, index); + + match = cmd_filter_by_string (vector_slot (vline, index), + cmd_vector, index); + + /* If command meets '.VARARG' then finish matching. */ + if (match == vararg_match) + break; + + ret = is_cmd_ambiguous (command, cmd_vector, index, match); + if (ret == 1) + { + vector_free (cmd_vector); + return CMD_ERR_AMBIGUOUS; + } + if (ret == 2) + { + vector_free (cmd_vector); + return CMD_ERR_NO_MATCH; + } + } + + /* Check matched count. */ + matched_element = NULL; + matched_count = 0; + incomplete_count = 0; + for (i = 0; i < vector_max (cmd_vector); i++) + if (vector_slot (cmd_vector,i) != NULL) + { + cmd_element = vector_slot (cmd_vector,i); + + if (match == vararg_match || index >= cmd_element->cmdsize) + { + matched_element = cmd_element; + matched_count++; + } + else + incomplete_count++; + } + + /* Finish of using cmd_vector. */ + vector_free (cmd_vector); + + /* To execute command, matched_count must be 1.*/ + if (matched_count == 0) + { + if (incomplete_count) + return CMD_ERR_INCOMPLETE; + else + return CMD_ERR_NO_MATCH; + } + + if (matched_count > 1) + return CMD_ERR_AMBIGUOUS; + + /* Argument treatment */ + varflag = 0; + argc = 0; + + for (i = 0; i < vector_max (vline); i++) + { + if (varflag) + argv[argc++] = vector_slot (vline, i); + else + { + vector descvec = vector_slot (matched_element->strvec, i); + + if (vector_max (descvec) == 1) + { + struct desc *desc = vector_slot (descvec, 0); + char *str = desc->cmd; + + if (CMD_VARARG (str)) + varflag = 1; + + if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str)) + argv[argc++] = vector_slot (vline, i); + } + else + argv[argc++] = vector_slot (vline, i); + } + + if (argc >= CMD_ARGC_MAX) + return CMD_ERR_EXEED_ARGC_MAX; + } + + /* For vtysh execution. */ + if (cmd) + *cmd = matched_element; + + if (matched_element->daemon) + return CMD_SUCCESS_DAEMON; + + /* Now execute matched command */ + return (*matched_element->func) (matched_element, vty, argc, argv); +} + +/* Configration make from file. */ +int +config_from_file (struct vty *vty, FILE *fp) +{ + int ret; + vector vline; + + while (fgets (vty->buf, VTY_BUFSIZ, fp)) + { + vline = cmd_make_strvec (vty->buf); + + /* In case of comment line */ + if (vline == NULL) + continue; + /* Execute configuration command : this is strict match */ + ret = cmd_execute_command_strict (vline, vty, NULL); + + /* Try again with setting node to CONFIG_NODE */ + if (ret != CMD_SUCCESS && ret != CMD_WARNING) + { + if (vty->node == KEYCHAIN_KEY_NODE) + { + vty->node = KEYCHAIN_NODE; + + ret = cmd_execute_command_strict (vline, vty, NULL); + + if (ret != CMD_SUCCESS && ret != CMD_WARNING) + { + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, NULL); + } + } + else + { + vty->node = CONFIG_NODE; + ret = cmd_execute_command_strict (vline, vty, NULL); + } + } + + cmd_free_strvec (vline); + + if (ret != CMD_SUCCESS && ret != CMD_WARNING) + return ret; + } + return CMD_SUCCESS; +} + +/* Configration from terminal */ +DEFUN (config_terminal, + config_terminal_cmd, + "configure terminal", + "Configuration from vty interface\n" + "Configuration terminal\n") +{ + if (vty_config_lock (vty)) + vty->node = CONFIG_NODE; + else + { + vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +/* Enable command */ +DEFUN (enable, + config_enable_cmd, + "enable", + "Turn on privileged mode command\n") +{ + /* If enable password is NULL, change to ENABLE_NODE */ + if ((host.enable == NULL && host.enable_encrypt == NULL) || + vty->type == VTY_SHELL_SERV) + vty->node = ENABLE_NODE; + else + vty->node = AUTH_ENABLE_NODE; + + return CMD_SUCCESS; +} + +/* Disable command */ +DEFUN (disable, + config_disable_cmd, + "disable", + "Turn off privileged mode command\n") +{ + if (vty->node == ENABLE_NODE) + vty->node = VIEW_NODE; + return CMD_SUCCESS; +} + +/* Down vty node level. */ +DEFUN (config_exit, + config_exit_cmd, + "exit", + "Exit current mode and down to previous mode\n") +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + if (vty_shell (vty)) + exit (0); + else + vty->status = VTY_CLOSE; + break; + case CONFIG_NODE: + vty->node = ENABLE_NODE; + vty_config_unlock (vty); + break; + case INTERFACE_NODE: + case ZEBRA_NODE: + case BGP_NODE: + case RIP_NODE: + case RIPNG_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case 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: + vty->node = BGP_NODE; + break; + case KEYCHAIN_KEY_NODE: + vty->node = KEYCHAIN_NODE; + break; + default: + break; + } + return CMD_SUCCESS; +} + +/* quit is alias of exit. */ +ALIAS (config_exit, + config_quit_cmd, + "quit", + "Exit current mode and down to previous mode\n") + +/* End of configuration. */ +DEFUN (config_end, + config_end_cmd, + "end", + "End current mode and change to enable mode.") +{ + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case 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, "Zebra %s (%s).%s", ZEBRA_VERSION, + host_name, + VTY_NEWLINE); + vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +/* Help display function for all node. */ +DEFUN (config_help, + config_help_cmd, + "help", + "Description of the interactive help system\n") +{ + vty_out (vty, + "Zebra VTY provides advanced help feature. When you need help,%s\ +anytime at the command line please press '?'.%s\ +%s\ +If nothing matches, the help list will be empty and you must backup%s\ + until entering a '?' shows the available options.%s\ +Two styles of help are provided:%s\ +1. Full help is available when you are ready to enter a%s\ +command argument (e.g. 'show ?') and describes each possible%s\ +argument.%s\ +2. Partial help is provided when an abbreviated argument is entered%s\ + and you want to know what arguments match the input%s\ + (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Help display function for all node. */ +DEFUN (config_list, + config_list_cmd, + "list", + "Print command list\n") +{ + int i; + struct cmd_node *cnode = vector_slot (cmdvec, vty->node); + struct cmd_element *cmd; + + for (i = 0; i < vector_max (cnode->cmd_vector); i++) + if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL) + vty_out (vty, " %s%s", cmd->string, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Write current configuration into file. */ +DEFUN (config_write_file, + config_write_file_cmd, + "write file", + "Write running configuration to memory, network, or terminal\n" + "Write to configuration file\n") +{ + int i; + int fd; + struct cmd_node *node; + char *config_file; + char *config_file_tmp = NULL; + char *config_file_sav = NULL; + struct vty *file_vty; + + /* Check and see if we are operating under vtysh configuration */ + if (host.config == NULL) + { + vty_out (vty, "Can't save to configuration file, using vtysh.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* Get filename. */ + config_file = host.config; + + config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1); + strcpy (config_file_sav, config_file); + strcat (config_file_sav, CONF_BACKUP_EXT); + + + config_file_tmp = malloc (strlen (config_file) + 8); + sprintf (config_file_tmp, "%s.XXXXXX", config_file); + + /* Open file to configuration write. */ + fd = mkstemp (config_file_tmp); + if (fd < 0) + { + vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp, + VTY_NEWLINE); + free (config_file_tmp); + free (config_file_sav); + return CMD_WARNING; + } + + /* Make vty for configuration file. */ + file_vty = vty_new (); + file_vty->fd = fd; + file_vty->type = VTY_FILE; + + /* Config file header print. */ + vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! "); + vty_time_print (file_vty, 1); + vty_out (file_vty, "!\n"); + + for (i = 0; i < vector_max (cmdvec); i++) + if ((node = vector_slot (cmdvec, i)) && node->func) + { + if ((*node->func) (file_vty)) + vty_out (file_vty, "!\n"); + } + vty_close (file_vty); + + if (unlink (config_file_sav) != 0) + if (errno != ENOENT) + { + vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + if (link (config_file, config_file_sav) != 0) + { + vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + sync (); + if (unlink (config_file) != 0) + { + vty_out (vty, "Can't unlink configuration file %s.%s", config_file, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + if (link (config_file_tmp, config_file) != 0) + { + vty_out (vty, "Can't save configuration file %s.%s", config_file, + VTY_NEWLINE); + free (config_file_sav); + free (config_file_tmp); + unlink (config_file_tmp); + return CMD_WARNING; + } + unlink (config_file_tmp); + sync (); + + free (config_file_sav); + free (config_file_tmp); + vty_out (vty, "Configuration saved to %s%s", config_file, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +ALIAS (config_write_file, + config_write_cmd, + "write", + "Write running configuration to memory, network, or terminal\n") + +ALIAS (config_write_file, + config_write_memory_cmd, + "write memory", + "Write running configuration to memory, network, or terminal\n" + "Write configuration to the file (same as write file)\n") + +ALIAS (config_write_file, + copy_runningconfig_startupconfig_cmd, + "copy running-config startup-config", + "Copy configuration\n" + "Copy running config to... \n" + "Copy running config to startup config (same as write file)\n") + +/* Write current configuration into the terminal. */ +DEFUN (config_write_terminal, + config_write_terminal_cmd, + "write terminal", + "Write running configuration to memory, network, or terminal\n" + "Write to terminal\n") +{ + int i; + struct cmd_node *node; + + if (vty->type == VTY_SHELL_SERV) + { + for (i = 0; i < vector_max (cmdvec); i++) + if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh) + { + if ((*node->func) (vty)) + vty_out (vty, "!%s", VTY_NEWLINE); + } + } + else + { + vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE, + VTY_NEWLINE); + vty_out (vty, "!%s", VTY_NEWLINE); + + for (i = 0; i < vector_max (cmdvec); i++) + if ((node = vector_slot (cmdvec, i)) && node->func) + { + if ((*node->func) (vty)) + vty_out (vty, "!%s", VTY_NEWLINE); + } + vty_out (vty, "end%s",VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* Write current configuration into the terminal. */ +ALIAS (config_write_terminal, + show_running_config_cmd, + "show running-config", + SHOW_STR + "running configuration\n") + +/* Write startup configuration into the terminal. */ +DEFUN (show_startup_config, + show_startup_config_cmd, + "show startup-config", + SHOW_STR + "Contentes of startup configuration\n") +{ + char buf[BUFSIZ]; + FILE *confp; + + confp = fopen (host.config, "r"); + if (confp == NULL) + { + vty_out (vty, "Can't open configuration file [%s]%s", + host.config, VTY_NEWLINE); + return CMD_WARNING; + } + + while (fgets (buf, BUFSIZ, confp)) + { + char *cp = buf; + + while (*cp != '\r' && *cp != '\n' && *cp != '\0') + cp++; + *cp = '\0'; + + vty_out (vty, "%s%s", buf, VTY_NEWLINE); + } + + fclose (confp); + + return CMD_SUCCESS; +} + +/* Hostname configuration */ +DEFUN (config_hostname, + hostname_cmd, + "hostname WORD", + "Set system's network name\n" + "This system's network name\n") +{ + if (!isalpha((int) *argv[0])) + { + vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.name) + XFREE (0, host.name); + + host.name = strdup (argv[0]); + return CMD_SUCCESS; +} + +DEFUN (config_no_hostname, + no_hostname_cmd, + "no hostname [HOSTNAME]", + NO_STR + "Reset system's network name\n" + "Host name of this router\n") +{ + if (host.name) + XFREE (0, host.name); + host.name = NULL; + return CMD_SUCCESS; +} + +/* VTY interface password set. */ +DEFUN (config_password, password_cmd, + "password (8|) WORD", + "Assign the terminal connection password\n" + "Specifies a HIDDEN password will follow\n" + "dummy string \n" + "The HIDDEN line password string\n") +{ + /* Argument check. */ + if (argc == 0) + { + vty_out (vty, "Please specify password.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (argc == 2) + { + if (*argv[0] == '8') + { + if (host.password) + XFREE (0, host.password); + host.password = NULL; + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = XSTRDUP (0, strdup (argv[1])); + return CMD_SUCCESS; + } + else + { + vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (!isalnum ((int) *argv[0])) + { + vty_out (vty, + "Please specify string starting with alphanumeric%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.password) + XFREE (0, host.password); + host.password = NULL; + + if (host.encrypt) + { + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = XSTRDUP (0, zencrypt (argv[0])); + } + else + host.password = XSTRDUP (0, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (config_password, password_text_cmd, + "password LINE", + "Assign the terminal connection password\n" + "The UNENCRYPTED (cleartext) line password\n") + +/* VTY enable password set. */ +DEFUN (config_enable_password, enable_password_cmd, + "enable password (8|) WORD", + "Modify enable password parameters\n" + "Assign the privileged level password\n" + "Specifies a HIDDEN password will follow\n" + "dummy string \n" + "The HIDDEN 'enable' password string\n") +{ + /* Argument check. */ + if (argc == 0) + { + vty_out (vty, "Please specify password.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Crypt type is specified. */ + if (argc == 2) + { + if (*argv[0] == '8') + { + if (host.enable) + XFREE (0, host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = XSTRDUP (0, argv[1]); + + return CMD_SUCCESS; + } + else + { + vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (!isalnum ((int) *argv[0])) + { + vty_out (vty, + "Please specify string starting with alphanumeric%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (host.enable) + XFREE (0, host.enable); + host.enable = NULL; + + /* Plain password input. */ + if (host.encrypt) + { + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0])); + } + else + host.enable = XSTRDUP (0, argv[0]); + + return CMD_SUCCESS; +} + +ALIAS (config_enable_password, + enable_password_text_cmd, + "enable password LINE", + "Modify enable password parameters\n" + "Assign the privileged level password\n" + "The UNENCRYPTED (cleartext) 'enable' password\n") + +/* VTY enable password delete. */ +DEFUN (no_config_enable_password, no_enable_password_cmd, + "no enable password", + NO_STR + "Modify enable password parameters\n" + "Assign the privileged level password\n") +{ + if (host.enable) + XFREE (0, host.enable); + host.enable = NULL; + + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = NULL; + + return CMD_SUCCESS; +} + +DEFUN (service_password_encrypt, + service_password_encrypt_cmd, + "service password-encryption", + "Set up miscellaneous service\n" + "Enable encrypted passwords\n") +{ + if (host.encrypt) + return CMD_SUCCESS; + + host.encrypt = 1; + + if (host.password) + { + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = XSTRDUP (0, zencrypt (host.password)); + } + if (host.enable) + { + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable)); + } + + return CMD_SUCCESS; +} + +DEFUN (no_service_password_encrypt, + no_service_password_encrypt_cmd, + "no service password-encryption", + NO_STR + "Set up miscellaneous service\n" + "Enable encrypted passwords\n") +{ + if (! host.encrypt) + return CMD_SUCCESS; + + host.encrypt = 0; + + if (host.password_encrypt) + XFREE (0, host.password_encrypt); + host.password_encrypt = NULL; + + if (host.enable_encrypt) + XFREE (0, host.enable_encrypt); + host.enable_encrypt = NULL; + + return CMD_SUCCESS; +} + +DEFUN (config_terminal_length, config_terminal_length_cmd, + "terminal length <0-512>", + "Set terminal line parameters\n" + "Set number of lines on a screen\n" + "Number of lines on screen (0 for no pausing)\n") +{ + int lines; + char *endptr = NULL; + + lines = strtol (argv[0], &endptr, 10); + if (lines < 0 || lines > 512 || *endptr != '\0') + { + vty_out (vty, "length is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty->lines = lines; + + return CMD_SUCCESS; +} + +DEFUN (config_terminal_no_length, config_terminal_no_length_cmd, + "terminal no length", + "Set terminal line parameters\n" + NO_STR + "Set number of lines on a screen\n") +{ + vty->lines = -1; + return CMD_SUCCESS; +} + +DEFUN (service_terminal_length, service_terminal_length_cmd, + "service terminal-length <0-512>", + "Set up miscellaneous service\n" + "System wide terminal length configuration\n" + "Number of lines of VTY (0 means no line control)\n") +{ + int lines; + char *endptr = NULL; + + lines = strtol (argv[0], &endptr, 10); + if (lines < 0 || lines > 512 || *endptr != '\0') + { + vty_out (vty, "length is malformed%s", VTY_NEWLINE); + return CMD_WARNING; + } + host.lines = lines; + + return CMD_SUCCESS; +} + +DEFUN (no_service_terminal_length, no_service_terminal_length_cmd, + "no service terminal-length [<0-512>]", + NO_STR + "Set up miscellaneous service\n" + "System wide terminal length configuration\n" + "Number of lines of VTY (0 means no line control)\n") +{ + host.lines = -1; + return CMD_SUCCESS; +} + +DEFUN (config_log_stdout, + config_log_stdout_cmd, + "log stdout", + "Logging control\n" + "Logging goes to stdout\n") +{ + zlog_set_flag (NULL, ZLOG_STDOUT); + host.log_stdout = 1; + return CMD_SUCCESS; +} + +DEFUN (no_config_log_stdout, + no_config_log_stdout_cmd, + "no log stdout", + NO_STR + "Logging control\n" + "Cancel logging to stdout\n") +{ + zlog_reset_flag (NULL, ZLOG_STDOUT); + host.log_stdout = 0; + return CMD_SUCCESS; +} + +DEFUN (config_log_file, + config_log_file_cmd, + "log file FILENAME", + "Logging control\n" + "Logging to file\n" + "Logging filename\n") +{ + int ret; + char *cwd; + char *fullpath; + + /* Path detection. */ + if (! IS_DIRECTORY_SEP (*argv[0])) + { + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (argv[0]) + 2); + sprintf (fullpath, "%s/%s", cwd, argv[0]); + } + else + fullpath = argv[0]; + + ret = zlog_set_file (NULL, ZLOG_FILE, fullpath); + + if (!ret) + { + vty_out (vty, "can't open logfile %s\n", argv[0]); + return CMD_WARNING; + } + + if (host.logfile) + XFREE (MTYPE_TMP, host.logfile); + + host.logfile = strdup (argv[0]); + + return CMD_SUCCESS; +} + +DEFUN (no_config_log_file, + no_config_log_file_cmd, + "no log file [FILENAME]", + NO_STR + "Logging control\n" + "Cancel logging to file\n" + "Logging file name\n") +{ + zlog_reset_file (NULL); + + if (host.logfile) + XFREE (MTYPE_TMP, host.logfile); + + host.logfile = NULL; + + return CMD_SUCCESS; +} + +DEFUN (config_log_syslog, + config_log_syslog_cmd, + "log syslog", + "Logging control\n" + "Logging goes to syslog\n") +{ + zlog_set_flag (NULL, ZLOG_SYSLOG); + host.log_syslog = 1; + return CMD_SUCCESS; +} + +DEFUN (no_config_log_syslog, + no_config_log_syslog_cmd, + "no log syslog", + NO_STR + "Logging control\n" + "Cancel logging to syslog\n") +{ + zlog_reset_flag (NULL, ZLOG_SYSLOG); + host.log_syslog = 0; + return CMD_SUCCESS; +} + +DEFUN (config_log_trap, + config_log_trap_cmd, + "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)", + "Logging control\n" + "Limit logging to specifed level\n") +{ + int new_level ; + + for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ ) + { + if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 ) + /* found new logging level */ + { + zlog_default->maskpri = new_level; + return CMD_SUCCESS; + } + } + return CMD_ERR_NO_MATCH; +} + +DEFUN (no_config_log_trap, + no_config_log_trap_cmd, + "no log trap", + NO_STR + "Logging control\n" + "Permit all logging information\n") +{ + zlog_default->maskpri = LOG_DEBUG; + return CMD_SUCCESS; +} + +DEFUN (config_log_record_priority, + config_log_record_priority_cmd, + "log record-priority", + "Logging control\n" + "Log the priority of the message within the message\n") +{ + zlog_default->record_priority = 1 ; + return CMD_SUCCESS; +} + +DEFUN (no_config_log_record_priority, + no_config_log_record_priority_cmd, + "no log record-priority", + NO_STR + "Logging control\n" + "Do not log the priority of the message within the message\n") +{ + zlog_default->record_priority = 0 ; + return CMD_SUCCESS; +} + + +DEFUN (banner_motd_default, + banner_motd_default_cmd, + "banner motd default", + "Set banner string\n" + "Strings for motd\n" + "Default string\n") +{ + host.motd = default_motd; + return CMD_SUCCESS; +} + +DEFUN (no_banner_motd, + no_banner_motd_cmd, + "no banner motd", + NO_STR + "Set banner string\n" + "Strings for motd\n") +{ + host.motd = NULL; + return CMD_SUCCESS; +} + +/* Set config filename. Called from vty.c */ +void +host_config_set (char *filename) +{ + host.config = strdup (filename); +} + +void +install_default (enum node_type node) +{ + install_element (node, &config_exit_cmd); + install_element (node, &config_quit_cmd); + install_element (node, &config_end_cmd); + install_element (node, &config_help_cmd); + install_element (node, &config_list_cmd); + + install_element (node, &config_write_terminal_cmd); + install_element (node, &config_write_file_cmd); + install_element (node, &config_write_memory_cmd); + install_element (node, &config_write_cmd); +} + +/* Initialize command interface. Install basic nodes and commands. */ +void +cmd_init (int terminal) +{ + /* Allocate initial top vector of commands. */ + cmdvec = vector_init (VECTOR_MIN_SIZE); + + /* Default host value settings. */ + host.name = NULL; + host.password = NULL; + host.enable = NULL; + host.logfile = NULL; + host.config = NULL; + host.lines = -1; + host.motd = default_motd; + + /* Install top nodes. */ + install_node (&view_node, NULL); + install_node (&enable_node, NULL); + install_node (&auth_node, NULL); + install_node (&auth_enable_node, NULL); + install_node (&config_node, config_write_host); + + /* Each node's basic commands. */ + install_element (VIEW_NODE, &show_version_cmd); + if (terminal) + { + install_element (VIEW_NODE, &config_list_cmd); + install_element (VIEW_NODE, &config_exit_cmd); + install_element (VIEW_NODE, &config_quit_cmd); + install_element (VIEW_NODE, &config_help_cmd); + install_element (VIEW_NODE, &config_enable_cmd); + install_element (VIEW_NODE, &config_terminal_length_cmd); + install_element (VIEW_NODE, &config_terminal_no_length_cmd); + } + + if (terminal) + { + install_default (ENABLE_NODE); + install_element (ENABLE_NODE, &config_disable_cmd); + install_element (ENABLE_NODE, &config_terminal_cmd); + install_element (ENABLE_NODE, &show_running_config_cmd); + install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); + } + install_element (ENABLE_NODE, &show_startup_config_cmd); + install_element (ENABLE_NODE, &show_version_cmd); + install_element (ENABLE_NODE, &config_terminal_length_cmd); + install_element (ENABLE_NODE, &config_terminal_no_length_cmd); + + if (terminal) + install_default (CONFIG_NODE); + install_element (CONFIG_NODE, &hostname_cmd); + install_element (CONFIG_NODE, &no_hostname_cmd); + install_element (CONFIG_NODE, &password_cmd); + install_element (CONFIG_NODE, &password_text_cmd); + install_element (CONFIG_NODE, &enable_password_cmd); + install_element (CONFIG_NODE, &enable_password_text_cmd); + install_element (CONFIG_NODE, &no_enable_password_cmd); + if (terminal) + { + install_element (CONFIG_NODE, &config_log_stdout_cmd); + install_element (CONFIG_NODE, &no_config_log_stdout_cmd); + install_element (CONFIG_NODE, &config_log_file_cmd); + install_element (CONFIG_NODE, &no_config_log_file_cmd); + install_element (CONFIG_NODE, &config_log_syslog_cmd); + install_element (CONFIG_NODE, &no_config_log_syslog_cmd); + install_element (CONFIG_NODE, &config_log_trap_cmd); + install_element (CONFIG_NODE, &no_config_log_trap_cmd); + install_element (CONFIG_NODE, &config_log_record_priority_cmd); + install_element (CONFIG_NODE, &no_config_log_record_priority_cmd); + install_element (CONFIG_NODE, &service_password_encrypt_cmd); + install_element (CONFIG_NODE, &no_service_password_encrypt_cmd); + install_element (CONFIG_NODE, &banner_motd_default_cmd); + install_element (CONFIG_NODE, &no_banner_motd_cmd); + install_element (CONFIG_NODE, &service_terminal_length_cmd); + install_element (CONFIG_NODE, &no_service_terminal_length_cmd); + } + + srand(time(NULL)); +} diff --git a/isisd/modified/command.h b/isisd/modified/command.h new file mode 100644 index 00000000..d407c5a9 --- /dev/null +++ b/isisd/modified/command.h @@ -0,0 +1,311 @@ +/* + * Zebra configuration command interface routine + * Copyright (C) 1997, 98 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_COMMAND_H +#define _ZEBRA_COMMAND_H + +#include "vector.h" +#include "vty.h" + +/* Host configuration variable */ +struct host +{ + /* Host name of this router. */ + char *name; + + /* Password for vty interface. */ + char *password; + char *password_encrypt; + + /* Enable password */ + char *enable; + char *enable_encrypt; + + /* System wide terminal lines. */ + int lines; + + /* Log filename. */ + char *logfile; + + /* Log stdout. */ + u_char log_stdout; + + /* Log syslog. */ + u_char log_syslog; + + /* config file name of this host */ + char *config; + + /* Flags for services */ + int advanced; + int encrypt; + + /* Banner configuration. */ + char *motd; +}; + +/* There are some command levels which called from command node. */ +enum node_type +{ + AUTH_NODE, /* Authentication mode of vty interface. */ + VIEW_NODE, /* View node. Default mode of vty interface. */ + AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ + ENABLE_NODE, /* Enable node. */ + CONFIG_NODE, /* Config node. Default mode of config file. */ + DEBUG_NODE, /* Debug node. */ + AAA_NODE, /* AAA node. */ + KEYCHAIN_NODE, /* Key-chain node. */ + KEYCHAIN_KEY_NODE, /* Key-chain key node. */ + INTERFACE_NODE, /* Interface mode node. */ + ZEBRA_NODE, /* zebra connection node. */ + TABLE_NODE, /* rtm_table selection node. */ + RIP_NODE, /* RIP protocol mode node. */ + RIPNG_NODE, /* RIPng protocol mode node. */ + BGP_NODE, /* BGP protocol mode which includes BGP4+ */ + BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */ + BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */ + BGP_IPV4M_NODE, /* BGP IPv4 multicast address family. */ + BGP_IPV6_NODE, /* BGP IPv6 address family */ + OSPF_NODE, /* OSPF protocol mode */ + OSPF6_NODE, /* OSPF protocol for IPv6 mode */ + ISIS_NODE, /* IS-IS 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. */ + VTY_NODE /* Vty node. */ +}; + +/* Node which has some commands and prompt string and configuration + function pointer . */ +struct cmd_node +{ + /* Node index. */ + enum node_type node; + + /* Prompt character at vty interface. */ + char *prompt; + + /* Is this node's configuration goes to vtysh ? */ + int vtysh; + + /* Node's configuration write function */ + int (*func) (struct vty *); + + /* Vector of this node's command list. */ + vector cmd_vector; +}; + +/* Structure of command element. */ +struct cmd_element +{ + char *string; /* Command specification by string. */ + int (*func) (struct cmd_element *, struct vty *, int, char **); + char *doc; /* Documentation of this command. */ + int daemon; /* Daemon to which this command belong. */ + vector strvec; /* Pointing out each description vector. */ + int cmdsize; /* Command index count. */ + char *config; /* Configuration string */ + vector subconfig; /* Sub configuration string */ +}; + +/* Command description structure. */ +struct desc +{ + char *cmd; /* Command string. */ + char *str; /* Command's description. */ +}; + +/* Return value of the commands. */ +#define CMD_SUCCESS 0 +#define CMD_WARNING 1 +#define CMD_ERR_NO_MATCH 2 +#define CMD_ERR_AMBIGUOUS 3 +#define CMD_ERR_INCOMPLETE 4 +#define CMD_ERR_EXEED_ARGC_MAX 5 +#define CMD_ERR_NOTHING_TODO 6 +#define CMD_COMPLETE_FULL_MATCH 7 +#define CMD_COMPLETE_MATCH 8 +#define CMD_COMPLETE_LIST_MATCH 9 +#define CMD_SUCCESS_DAEMON 10 + +/* Argc max counts. */ +#define CMD_ARGC_MAX 25 + +/* Turn off these macros when uisng cpp with extract.pl */ +#ifndef VTYSH_EXTRACT_PL + +/* DEFUN for vty command interafce. Little bit hacky ;-). */ +#define DEFUN(funcname, cmdname, cmdstr, helpstr) \ + int funcname (struct cmd_element *, struct vty *, int, char **); \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr \ + }; \ + int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, char **argv) + +/* DEFUN_NOSH for commands that vtysh should ignore */ +#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFUN(funcname, cmdname, cmdstr, helpstr) + +/* DEFSH for vtysh. */ +#define DEFSH(daemon, cmdname, cmdstr, helpstr) \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + NULL, \ + helpstr, \ + daemon \ + }; \ + +/* DEFUN + DEFSH */ +#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ + int funcname (struct cmd_element *, struct vty *, int, char **); \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr, \ + daemon \ + }; \ + int funcname \ + (struct cmd_element *self, struct vty *vty, int argc, char **argv) + +/* ALIAS macro which define existing command's alias. */ +#define ALIAS(funcname, cmdname, cmdstr, helpstr) \ + struct cmd_element cmdname = \ + { \ + cmdstr, \ + funcname, \ + helpstr \ + }; + +#endif /* VTYSH_EXTRACT_PL */ + +/* Some macroes */ +#define CMD_OPTION(S) ((S[0]) == '[') +#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<')) +#define CMD_VARARG(S) ((S[0]) == '.') +#define CMD_RANGE(S) ((S[0] == '<')) + +#define CMD_IPV4(S) ((strcmp ((S), "A.B.C.D") == 0)) +#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0)) +#define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) +#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) + +/* Common descriptions. */ +#define SHOW_STR "Show running system information\n" +#define IP_STR "IP information\n" +#define IPV6_STR "IPv6 information\n" +#define NO_STR "Negate a command or set its defaults\n" +#define CLEAR_STR "Reset functions\n" +#define RIP_STR "RIP information\n" +#define BGP_STR "BGP information\n" +#define OSPF_STR "OSPF information\n" +#define NEIGHBOR_STR "Specify neighbor router\n" +#define DEBUG_STR "Debugging functions (see also 'undebug')\n" +#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n" +#define ROUTER_STR "Enable a routing process\n" +#define AS_STR "AS number\n" +#define MBGP_STR "MBGP information\n" +#define MATCH_STR "Match values from routing table\n" +#define SET_STR "Set values in destination routing protocol\n" +#define OUT_STR "Filter outgoing routing updates\n" +#define IN_STR "Filter incoming routing updates\n" +#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n" +#define OSPF6_NUMBER_STR "Specify by number\n" +#define INTERFACE_STR "Interface infomation\n" +#define IFNAME_STR "Interface name(e.g. ep0)\n" +#define IP6_STR "IPv6 Information\n" +#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n" +#define OSPF6_ROUTER_STR "Enable a routing process\n" +#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n" +#define SECONDS_STR "<1-65535> Seconds\n" +#define ROUTE_STR "Routing Table\n" +#define PREFIX_LIST_STR "Build a prefix list\n" +#define OSPF6_DUMP_TYPE_LIST \ +"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)" +#define 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. */ +void install_node (struct cmd_node *, int (*) (struct vty *)); +void install_default (enum node_type); +void install_element (enum node_type, struct cmd_element *); +void sort_node (); + +char *argv_concat (char **, int, int); +vector cmd_make_strvec (char *); +void cmd_free_strvec (vector); +vector cmd_describe_command (); +char **cmd_complete_command (); +char *cmd_prompt (enum node_type); +int config_from_file (struct vty *, FILE *); +int cmd_execute_command (vector, struct vty *, struct cmd_element **); +int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **); +void config_replace_string (struct cmd_element *, char *, ...); +void cmd_init (int); + +/* Export typical functions. */ +extern struct cmd_element config_end_cmd; +extern struct cmd_element config_exit_cmd; +extern struct cmd_element config_quit_cmd; +extern struct cmd_element config_help_cmd; +extern struct cmd_element config_list_cmd; +int config_exit (struct cmd_element *, struct vty *, int, char **); +int config_help (struct cmd_element *, struct vty *, int, char **); +char *host_config_file (); +void host_config_set (char *); + +#endif /* _ZEBRA_COMMAND_H */ diff --git a/isisd/modified/config.h.in b/isisd/modified/config.h.in new file mode 100644 index 00000000..c06839ef --- /dev/null +++ b/isisd/modified/config.h.in @@ -0,0 +1,368 @@ +/* config.h.in. Generated from configure.in by autoheader. */ +/* accconfig.h -- `autoheader' will generate config.h.in for zebra. + Copyright (C) 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org> */ + +/* Version of GNU Zebra */ +#undef VERSION + +/* Solaris on x86. */ +#undef SOLARIS_X86 + +/* Package name of GNU Zebra */ +#undef PACKAGE + +/* Define if host is GNU/Linux */ +#undef GNU_LINUX + +/* Define if you have the AF_ROUTE socket. */ +#undef HAVE_AF_ROUTE + +/* Define if you have the inet_aton function. */ +#undef HAVE_INET_ATON + +/* Define if you have the inet_ntop function. */ +#undef HAVE_INET_NTOP + +/* Define if you have the inet_pton function. */ +#undef HAVE_INET_PTON + +/* Define if you have the setproctitle function. */ +#undef HAVE_SETPROCTITLE + +/* Define if you have ipv6 stack. */ +#undef HAVE_IPV6 + +/* Define if you wish to support ipv6 router advertisment. */ +/* #undef HAVE_RTADV */ + +/* whether system has GNU regex */ +#undef HAVE_GNU_REGEX + +/* whether system has SNMP library */ +#undef HAVE_SNMP + +/* whether sockaddr has a sa_len field */ +#undef HAVE_SA_LEN + +/* whether sockaddr_in has a sin_len field */ +#undef HAVE_SIN_LEN + +/* whether sockaddr_un has a sun_len field */ +#undef HAVE_SUN_LEN + +/* whether sockaddr_in6 has a sin6_scope_id field */ +#undef HAVE_SIN6_SCOPE_ID + +/* Define if there is socklen_t. */ +#undef HAVE_SOCKLEN_T + +/* Define if there is sockaddr_dl structure. */ +#undef HAVE_SOCKADDR_DL + +/* Define if there is ifaliasreq structure. */ +#undef HAVE_IFALIASREQ + +/* Define if there is in6_aliasreq structure. */ +#undef HAVE_IN6_ALIASREQ + +/* Define if there is rt_addrinfo structure. */ +#undef HAVE_RT_ADDRINFO + +/* Define if there is in_pktinfo structure. */ +#undef HAVE_INPKTINFO + +/* Define if you have the getrusage function. */ +#undef HAVE_RUSAGE + +/* Define if /proc/net/dev exists. */ +#undef HAVE_PROC_NET_DEV + +/* Define if /proc/net/if_inet6 exists. */ +#undef HAVE_PROC_NET_IF_INET6 + +/* Define if NET_RT_IFLIST exists in sys/socket.h. */ +#undef HAVE_NET_RT_IFLIST + +/* Define if you have INRIA ipv6 stack. */ +#undef INRIA_IPV6 + +/* Define if you have KAME project ipv6 stack. */ +#undef KAME + +/* Define if you have Linux ipv6 stack. */ +#undef LINUX_IPV6 + +/* Define if you have NRL ipv6 stack. */ +#undef NRL + +/* Define if you have BSDI NRL IPv6 stack. */ +#undef BSDI_NRL + +/* Define if one-vty option is specified. */ +#undef VTYSH + +/* Define if interface aliases don't have distinct indeces */ +#undef HAVE_BROKEN_ALIASES + +/* Define if disable-bgp-announce option is specified. */ +#undef DISABLE_BGP_ANNOUNCE + +/* PAM support */ +#undef USE_PAM + +/* TCP/IP communication between zebra and protocol daemon. */ +#undef HAVE_TCP_ZEBRA + +/* The OSPF NSSA option (RFC1587). */ +#undef HAVE_NSSA + +/* The OSPF Opaque LSA option (RFC2370). */ +#undef HAVE_OPAQUE_LSA + +/* Traffic Engineering Extension to OSPF + (draft-katz-yeung-ospf-traffic-06.txt). */ +#undef HAVE_OSPF_TE + +/* Linux netlink. */ +#undef HAVE_NETLINK + +/* PATHS */ +#undef PATH_ZEBRA_PID +#undef PATH_RIPD_PID +#undef PATH_RIPNGD_PID +#undef PATH_BGPD_PID +#undef PATH_OSPFD_PID +#undef PATH_OSPF6D_PID +#undef PATH_ISISD_PID + +/* Define if Solaris */ +#undef SUNOS_5 + +/* Define if FreeBSD 3.2 */ +#undef FREEBSD_32 + +/* Define if OpenBSD */ +#undef OPEN_BSD + +#ifdef HAVE_IPV6 +#ifdef KAME +#ifndef INET6 +#define INET6 +#endif /* INET6 */ +#endif /* KAME */ +#endif /* HAVE_IPV6 */ + +#ifdef SUNOS_5 +typedef unsigned int u_int32_t; +typedef unsigned short u_int16_t; +typedef unsigned short u_int8_t; +#endif /* SUNOS_5 */ + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif /* HAVE_SOCKLEN_T */ + +/* Define to 1 if you have the <asm/types.h> header file. */ +#undef HAVE_ASM_TYPES_H + +/* Define to 1 if you have the `bcopy' function. */ +#undef HAVE_BCOPY + +/* Define to 1 if you have the `bzero' function. */ +#undef HAVE_BZERO + +/* Define to 1 if you have the `daemon' function. */ +#undef HAVE_DAEMON + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `getifaddrs' function. */ +#undef HAVE_GETIFADDRS + +/* Define to 1 if you have the `if_indextoname' function. */ +#undef HAVE_IF_INDEXTONAME + +/* Define to 1 if you have the `if_nametoindex' function. */ +#undef HAVE_IF_NAMETOINDEX + +/* Define to 1 if you have the `inet_aton' function. */ +#undef HAVE_INET_ATON + +/* Define to 1 if you have the <inet/nd.h> header file. */ +#undef HAVE_INET_ND_H + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <kvm.h> header file. */ +#undef HAVE_KVM_H + +/* Define to 1 if you have the `crypt' library (-lcrypt). */ +#undef HAVE_LIBCRYPT + +/* Define to 1 if you have the `kvm' library (-lkvm). */ +#undef HAVE_LIBKVM + +/* Define to 1 if you have the `m' library (-lm). */ +#undef HAVE_LIBM + +/* Define to 1 if you have the `ncurses' library (-lncurses). */ +#undef HAVE_LIBNCURSES + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `readline' library (-lreadline). */ +#undef HAVE_LIBREADLINE + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `tinfo' library (-ltinfo). */ +#undef HAVE_LIBTINFO + +/* Define to 1 if you have the <libutil.h> header file. */ +#undef HAVE_LIBUTIL_H + +/* Define to 1 if you have the `xnet' library (-lxnet). */ +#undef HAVE_LIBXNET + +/* Define to 1 if you have the <linux/version.h> header file. */ +#undef HAVE_LINUX_VERSION_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the <netdb.h> header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the <netinet6/nd6.h> header file. */ +#undef HAVE_NETINET6_ND6_H + +/* Define to 1 if you have the <netinet/icmp6.h> header file. */ +#undef HAVE_NETINET_ICMP6_H + +/* Define to 1 if you have the <netinet/in6.h> header file. */ +#undef HAVE_NETINET_IN6_H + +/* Define to 1 if you have the <netinet/in6_var.h> header file. */ +#undef HAVE_NETINET_IN6_VAR_H + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the <netinet/in_var.h> header file. */ +#undef HAVE_NETINET_IN_VAR_H + +/* Define to 1 if you have the <net/if_dl.h> header file. */ +#undef HAVE_NET_IF_DL_H + +/* Define to 1 if you have the <net/if_var.h> header file. */ +#undef HAVE_NET_IF_VAR_H + +/* Define to 1 if you have the <net/netopt.h> header file. */ +#undef HAVE_NET_NETOPT_H + +/* Define to 1 if you have the `setproctitle' function. */ +#undef HAVE_SETPROCTITLE + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> 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 <stropts.h> header file. */ +#undef HAVE_STROPTS_H + +/* Define to 1 if you have the <sys/conf.h> header file. */ +#undef HAVE_SYS_CONF_H + +/* Define to 1 if you have the <sys/ksym.h> header file. */ +#undef HAVE_SYS_KSYM_H + +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/sockio.h> header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/sysctl.h> header file. */ +#undef HAVE_SYS_SYSCTL_H + +/* Define to 1 if you have the <sys/times.h> header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/isisd/modified/configure b/isisd/modified/configure new file mode 100755 index 00000000..e4bf6d4f --- /dev/null +++ b/isisd/modified/configure @@ -0,0 +1,8277 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.53. +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + + +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# NLS nuisances. +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +(set +x; test -n "`(LANG=C; export LANG) 2>&1`") && + { $as_unset LANG || test "${LANG+set}" != set; } || + { LANG=C; export LANG; } +(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") && + { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } || + { LC_ALL=C; export LC_ALL; } +(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") && + { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } || + { LC_TIME=C; export LC_TIME; } +(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") && + { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } || + { LC_CTYPE=C; export LC_CTYPE; } +(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") && + { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } || + { LANGUAGE=C; export LANGUAGE; } +(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") && + { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } || + { LC_COLLATE=C; export LC_COLLATE; } +(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") && + { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } || + { LC_NUMERIC=C; export LC_NUMERIC; } +(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") && + { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } || + { LC_MESSAGES=C; export LC_MESSAGES; } + + +# Name of the executable. +as_me=`(basename "$0") 2>/dev/null || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conftest.sh + echo "exit 0" >>conftest.sh + chmod +x conftest.sh + if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conftest.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="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="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; } + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="lib/zebra.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#else +# if HAVE_STDINT_H +# include <stdint.h> +# endif +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif" + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors + --enable-vtysh, Make integrated VTY version of zebra + --disable-ipv6 turn off IPv6 related features and daemons + --disable-zebra do not build zebra daemon + --disable-bgpd do not build bgpd + --disable-ripd do not build ripd + --disable-ripngd do not build ripngd + --disable-ospfd do not build ospfd + --disable-ospf6d do not build ospf6d + --disable-isisd do not build isisd + --disable-bgp-announce, turn off BGP route announcement + --enable-netlink force to use Linux netlink interface + --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X + --enable-snmp enable SNMP support + --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon + --enable-nssa enable OSPF NSSA option + --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370) + --enable-ospf-te enable Traffic Engineering Extension to OSPF + --enable-multipath=ARG enable multipath function, ARG must be digit + +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-libpam use libpam for PAM support in vtysh + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have + headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.53. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell meta-characters. +ac_configure_args= +ac_sep= +for ac_arg +do + case $ac_arg in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n ) continue ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + ac_sep=" " ;; + esac + # Get rid of the leading space. +done + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core core.* *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + +am__api_version="1.6" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="${MAKE}"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + # test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# Define the identity of the package. + PACKAGE=zebra + VERSION=0.93 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + +# Add the stamp file to the list of files AC keeps track of, +# along with our hook. +ac_config_headers="$ac_config_headers config.h" + + + + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + + + +# Check whether --with-cflags or --without-cflags was given. +if test "${with_cflags+set}" = set; then + withval="$with_cflags" + +fi; +if test "x$with_cflags" != "x" ; then + CFLAGS="$with_cflags" ; cflags_specified=yes ; +elif test -n "$CFLAGS" ; then + cflags_specified=yes ; +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$as_dir/$ac_word" ${1+"$@"} + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output" >&5 +echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +for ac_file in `ls a_out.exe a.exe conftest.exe 2>/dev/null; + ls a.out conftest 2>/dev/null; + ls a.* conftest.* 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb | *.xSYM ) ;; + a.out ) # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool --akim. + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables" >&5 +echo "$as_me: error: C compiler cannot create executables" >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include <stdlib.h>' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <stdlib.h> +$ac_declaration +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_declaration +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +rm -f .deps 2>/dev/null +mkdir .deps 2>/dev/null +if test -d .deps; then + DEPDIR=.deps +else + # MS-DOS does not allow filenames that begin with a dot. + DEPDIR=_deps +fi +rmdir .deps 2>/dev/null + + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +doit: + @echo done +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | fgrep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + echo '#include "conftest.h"' > conftest.c + echo 'int i;' > conftest.h + echo "${am__include} ${am__quote}conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=conftest.c object=conftest.o \ + depfile=conftest.Po tmpdepfile=conftest.TPo \ + $SHELL ./depcomp $depcc -c conftest.c -o conftest.o >/dev/null 2>&1 && + grep conftest.h conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if test "x$cflags_specified" = "x" ; then + CFLAGS="$CFLAGS -Wall" +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <assert.h> + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <assert.h> + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="${MAKE}"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + AR=$ac_ct_AR +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + + + +echo "$as_me:$LINENO: checking for AIX" >&5 +echo $ECHO_N "checking for AIX... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#ifdef _AIX + yes +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +cat >>confdefs.h <<\_ACEOF +#define _ALL_SOURCE 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + + +# Check whether --enable-vtysh or --disable-vtysh was given. +if test "${enable_vtysh+set}" = set; then + enableval="$enable_vtysh" + +fi; +# Check whether --enable-ipv6 or --disable-ipv6 was given. +if test "${enable_ipv6+set}" = set; then + enableval="$enable_ipv6" + +fi; +# Check whether --enable-zebra or --disable-zebra was given. +if test "${enable_zebra+set}" = set; then + enableval="$enable_zebra" + +fi; +# Check whether --enable-bgpd or --disable-bgpd was given. +if test "${enable_bgpd+set}" = set; then + enableval="$enable_bgpd" + +fi; +# Check whether --enable-ripd or --disable-ripd was given. +if test "${enable_ripd+set}" = set; then + enableval="$enable_ripd" + +fi; +# Check whether --enable-ripngd or --disable-ripngd was given. +if test "${enable_ripngd+set}" = set; then + enableval="$enable_ripngd" + +fi; +# Check whether --enable-ospfd or --disable-ospfd was given. +if test "${enable_ospfd+set}" = set; then + enableval="$enable_ospfd" + +fi; +# Check whether --enable-ospf6d or --disable-ospf6d was given. +if test "${enable_ospf6d+set}" = set; then + enableval="$enable_ospf6d" + +fi; +# Check whether --enable-isisd or --disable-isisd was given. +if test "${enable_isisd+set}" = set; then + enableval="$enable_isisd" + +fi; +# Check whether --enable-bgp-announce or --disable-bgp-announce was given. +if test "${enable_bgp_announce+set}" = set; then + enableval="$enable_bgp_announce" + +fi; +# Check whether --enable-netlink or --disable-netlink was given. +if test "${enable_netlink+set}" = set; then + enableval="$enable_netlink" + +fi; +# Check whether --enable-broken-aliases or --disable-broken-aliases was given. +if test "${enable_broken_aliases+set}" = set; then + enableval="$enable_broken_aliases" + +fi; +# Check whether --enable-snmp or --disable-snmp was given. +if test "${enable_snmp+set}" = set; then + enableval="$enable_snmp" + +fi; + +# Check whether --with-libpam or --without-libpam was given. +if test "${with_libpam+set}" = set; then + withval="$with_libpam" + +fi; +# Check whether --enable-tcpsock or --disable-tcpsock was given. +if test "${enable_tcpsock+set}" = set; then + enableval="$enable_tcpsock" + +fi; +# Check whether --enable-nssa or --disable-nssa was given. +if test "${enable_nssa+set}" = set; then + enableval="$enable_nssa" + +fi; +# Check whether --enable-opaque-lsa or --disable-opaque-lsa was given. +if test "${enable_opaque_lsa+set}" = set; then + enableval="$enable_opaque_lsa" + +fi; +# Check whether --enable-ospf-te or --disable-ospf-te was given. +if test "${enable_ospf_te+set}" = set; then + enableval="$enable_ospf_te" + +fi; +# Check whether --enable-multipath or --disable-multipath was given. +if test "${enable_multipath+set}" = set; then + enableval="$enable_multipath" + +fi; + + +if test "${enable_broken_aliases}" = "yes"; then + if test "${enable_netlink}" = "yes" + then + echo "Sorry, you can't use netlink with broken aliases" + exit 1 + fi + cat >>confdefs.h <<\_ACEOF +#define HAVE_BROKEN_ALIASES 1 +_ACEOF + + enable_netlink=no +fi + +if test "${enable_tcp_zebra}" = "yes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_TCP_ZEBRA 1 +_ACEOF + +fi + +if test "${enable_nssa}" = "yes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_NSSA 1 +_ACEOF + +fi + +if test "${enable_opaque_lsa}" = "yes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_OPAQUE_LSA 1 +_ACEOF + +fi + +if test "${enable_ospf_te}" = "yes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_OPAQUE_LSA 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define HAVE_OSPF_TE 1 +_ACEOF + +fi + + + +MULTIPATH_NUM=1 + +case "${enable_multipath}" in + [0-9]|[1-9][0-9]) + MULTIPATH_NUM="${enable_multipath}" + ;; + "") + ;; + *) + echo "Please specify digit to --enable-multipath ARG." + exit 1 + ;; +esac + + + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_Header=no" +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; + no:yes ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* 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; +} +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; +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +fi +rm -f conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_c_const=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_type_signal=int +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + +case "$host" in + *-sunos5.6* | *-solaris2.6*) + opsys=sol2-6 + cat >>confdefs.h <<\_ACEOF +#define SUNOS_5 1 +_ACEOF + + +echo "$as_me:$LINENO: checking for main in -lxnet" >&5 +echo $ECHO_N "checking for main in -lxnet... $ECHO_C" >&6 +if test "${ac_cv_lib_xnet_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lxnet $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_xnet_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_xnet_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_xnet_main" >&5 +echo "${ECHO_T}$ac_cv_lib_xnet_main" >&6 +if test $ac_cv_lib_xnet_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBXNET 1 +_ACEOF + + LIBS="-lxnet $LIBS" + +fi + + CURSES=-lcurses + ;; + *-sunos5* | *-solaris2*) + cat >>confdefs.h <<\_ACEOF +#define SUNOS_5 1 +_ACEOF + + +echo "$as_me:$LINENO: checking for main in -lsocket" >&5 +echo $ECHO_N "checking for main in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_socket_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_main" >&6 +if test $ac_cv_lib_socket_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for main in -lnsl" >&5 +echo $ECHO_N "checking for main in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_nsl_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_main" >&6 +if test $ac_cv_lib_nsl_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + CURSES=-lcurses + ;; + *-linux-*) + opsys=gnu-linux + cat >>confdefs.h <<\_ACEOF +#define GNU_LINUX 1 +_ACEOF + + ;; + *-nec-sysv4*) + +echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char gethostbyname (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_nsl_gethostbyname=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 +if test $ac_cv_lib_nsl_gethostbyname = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for socket in -lsocket" >&5 +echo $ECHO_N "checking for socket in -lsocket... $ECHO_C" >&6 +if test "${ac_cv_lib_socket_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +socket (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_socket_socket=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_socket_socket=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_socket_socket" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_socket" >&6 +if test $ac_cv_lib_socket_socket = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + ;; + *-freebsd3.2) + cat >>confdefs.h <<\_ACEOF +#define FREEBSD_32 1 +_ACEOF + + ;; + *-openbsd*) + opsys=openbsd + cat >>confdefs.h <<\_ACEOF +#define OPEN_BSD 1 +_ACEOF + + ;; + *-bsdi*) + opsys=bsdi + OTHER_METHOD="mtu_kvm.o" + +echo "$as_me:$LINENO: checking for main in -lkvm" >&5 +echo $ECHO_N "checking for main in -lkvm... $ECHO_C" >&6 +if test "${ac_cv_lib_kvm_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lkvm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_kvm_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_kvm_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_kvm_main" >&5 +echo "${ECHO_T}$ac_cv_lib_kvm_main" >&6 +if test $ac_cv_lib_kvm_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBKVM 1 +_ACEOF + + LIBS="-lkvm $LIBS" + +fi + + ;; +esac + +case "${host_cpu}-${host_os}" in + i?86-solaris*) + cat >>confdefs.h <<\_ACEOF +#define SOLARIS_X86 1 +_ACEOF + + ;; +esac + +case "${enable_vtysh}" in + "yes") VTYSH="vtysh"; + cat >>confdefs.h <<\_ACEOF +#define VTYSH 1 +_ACEOF + + +echo "$as_me:$LINENO: checking for tputs in -ltinfo" >&5 +echo $ECHO_N "checking for tputs in -ltinfo... $ECHO_C" >&6 +if test "${ac_cv_lib_tinfo_tputs+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ltinfo $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tputs (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +tputs (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_tinfo_tputs=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_tinfo_tputs=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_tinfo_tputs" >&5 +echo "${ECHO_T}$ac_cv_lib_tinfo_tputs" >&6 +if test $ac_cv_lib_tinfo_tputs = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBTINFO 1 +_ACEOF + + LIBS="-ltinfo $LIBS" + +else + +echo "$as_me:$LINENO: checking for tputs in -lncurses" >&5 +echo $ECHO_N "checking for tputs in -lncurses... $ECHO_C" >&6 +if test "${ac_cv_lib_ncurses_tputs+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lncurses $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tputs (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +tputs (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ncurses_tputs=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_ncurses_tputs=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tputs" >&5 +echo "${ECHO_T}$ac_cv_lib_ncurses_tputs" >&6 +if test $ac_cv_lib_ncurses_tputs = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNCURSES 1 +_ACEOF + + LIBS="-lncurses $LIBS" + +fi + +fi + + +echo "$as_me:$LINENO: checking for main in -lreadline" >&5 +echo $ECHO_N "checking for main in -lreadline... $ECHO_C" >&6 +if test "${ac_cv_lib_readline_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lreadline $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_readline_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_readline_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_readline_main" >&5 +echo "${ECHO_T}$ac_cv_lib_readline_main" >&6 +if test $ac_cv_lib_readline_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBREADLINE 1 +_ACEOF + + LIBS="-lreadline $LIBS" + +fi + + if test $ac_cv_lib_readline_main = no; then + { { echo "$as_me:$LINENO: error: vtysh needs libreadline but was not found on your system." >&5 +echo "$as_me: error: vtysh needs libreadline but was not found on your system." >&2;} + { (exit 1); exit 1; }; } + fi + if test "${ac_cv_header_readline_history_h+set}" = set; then + echo "$as_me:$LINENO: checking for readline/history.h" >&5 +echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6 +if test "${ac_cv_header_readline_history_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5 +echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking readline/history.h usability" >&5 +echo $ECHO_N "checking readline/history.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +$ac_includes_default +#include <readline/history.h> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking readline/history.h presence" >&5 +echo $ECHO_N "checking readline/history.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <readline/history.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: readline/history.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;};; + no:yes ) + { echo "$as_me:$LINENO: WARNING: readline/history.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: readline/history.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: readline/history.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: readline/history.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: readline/history.h: proceeding with the preprocessor's result" >&2;};; +esac +echo "$as_me:$LINENO: checking for readline/history.h" >&5 +echo $ECHO_N "checking for readline/history.h... $ECHO_C" >&6 +if test "${ac_cv_header_readline_history_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_readline_history_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_readline_history_h" >&5 +echo "${ECHO_T}$ac_cv_header_readline_history_h" >&6 + +fi + + + if test $ac_cv_header_readline_history_h = no;then + { { echo "$as_me:$LINENO: error: readline is too old to have readline/history.h, please update to the latest readline library." >&5 +echo "$as_me: error: readline is too old to have readline/history.h, please update to the latest readline library." >&2;} + { (exit 1); exit 1; }; } + fi + ;; + "no" ) VTYSH="";; + * ) ;; +esac + +if test "$with_libpam" = "yes"; then +echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5 +echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_pam_start+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pam_start (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +pam_start (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_pam_start=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_pam_pam_start=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6 +if test $ac_cv_lib_pam_pam_start = yes; then + echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5 +echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_misc_conv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char misc_conv (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +misc_conv (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_misc_conv=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_pam_misc_conv=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6 +if test $ac_cv_lib_pam_misc_conv = yes; then + cat >>confdefs.h <<\_ACEOF +#define USE_PAM 1 +_ACEOF + + LIBPAM="-lpam" +else + cat >>confdefs.h <<\_ACEOF +#define USE_PAM 1 +_ACEOF + + LIBPAM="-lpam -lpam_misc" + +fi + + +else + echo "$as_me:$LINENO: checking for pam_end in -lpam" >&5 +echo $ECHO_N "checking for pam_end in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_pam_end+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam -ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pam_end (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +pam_end (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_pam_end=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_pam_pam_end=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_end" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_pam_end" >&6 +if test $ac_cv_lib_pam_pam_end = yes; then + echo "$as_me:$LINENO: checking for misc_conv in -lpam" >&5 +echo $ECHO_N "checking for misc_conv in -lpam... $ECHO_C" >&6 +if test "${ac_cv_lib_pam_misc_conv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char misc_conv (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +misc_conv (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_pam_misc_conv=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_pam_misc_conv=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_pam_misc_conv" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_misc_conv" >&6 +if test $ac_cv_lib_pam_misc_conv = yes; then + cat >>confdefs.h <<\_ACEOF +#define USE_PAM 1 +_ACEOF + + LIBPAM="-lpam -ldl" +else + cat >>confdefs.h <<\_ACEOF +#define USE_PAM 1 +_ACEOF + + LIBPAM="-lpam -ldl -lpam_misc" + +fi + + +else + { echo "$as_me:$LINENO: WARNING: *** pam support will not be built ***" >&5 +echo "$as_me: WARNING: *** pam support will not be built ***" >&2;} +fi + + + +fi + +fi + + + + + + + + + + + + + + + + + +for ac_func in bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in setproctitle +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + echo "$as_me:$LINENO: checking for setproctitle in -lutil" >&5 +echo $ECHO_N "checking for setproctitle in -lutil... $ECHO_C" >&6 +if test "${ac_cv_lib_util_setproctitle+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lutil $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char setproctitle (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +setproctitle (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_util_setproctitle=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_util_setproctitle=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_util_setproctitle" >&5 +echo "${ECHO_T}$ac_cv_lib_util_setproctitle" >&6 +if test $ac_cv_lib_util_setproctitle = yes; then + LIBS="$LIBS -lutil"; cat >>confdefs.h <<\_ACEOF +#define HAVE_SETPROCTITLE 1 +_ACEOF + +fi + +fi +done + + +echo "$as_me:$LINENO: checking zebra between kernel interface method" >&5 +echo $ECHO_N "checking zebra between kernel interface method... $ECHO_C" >&6 +if test x"$opsys" = x"gnu-linux"; then + if test "${enable_netlink}" = "yes";then + echo "$as_me:$LINENO: result: netlink" >&5 +echo "${ECHO_T}netlink" >&6 + RT_METHOD=rt_netlink.o + cat >>confdefs.h <<\_ACEOF +#define HAVE_NETLINK 1 +_ACEOF + + netlink=yes + elif test "${enable_netlink}" = "no"; then + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 + RT_METHOD=rt_ioctl.o + netlink=no + else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <linux/autoconf.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE > 131328 /* 2.1.0 or later */ +#ifdef CONFIG_RTNETLINK + yes +#endif +#endif +#if LINUX_VERSION_CODE > 132112 /* 2.4.17 or later */ + yes +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: netlink" >&5 +echo "${ECHO_T}netlink" >&6 + RT_METHOD=rt_netlink.o + cat >>confdefs.h <<\_ACEOF +#define HAVE_NETLINK 1 +_ACEOF + + netlink=yes +else + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 + RT_METHOD=rt_ioctl.o +fi +rm -f conftest* + + fi +else + if test "$opsys" = "sol2-6";then + echo "$as_me:$LINENO: result: solaris" >&5 +echo "${ECHO_T}solaris" >&6 + KERNEL_METHOD="kernel_socket.o" + RT_METHOD="rt_socket.o" + else + if test "$cross_compiling" = yes; then + KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + echo "$as_me:$LINENO: result: socket" >&5 +echo "${ECHO_T}socket" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> + +main () +{ + int ac_sock; + + ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); + if (ac_sock < 0 && errno == EINVAL) + exit (1); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_AF_ROUTE 1 +_ACEOF + + KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + echo "$as_me:$LINENO: result: socket" >&5 +echo "${ECHO_T}socket" >&6 +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +( exit $ac_status ) +RT_METHOD=rt_ioctl.o + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 +fi +rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + fi +fi + + + + +echo "$as_me:$LINENO: checking route read method check" >&5 +echo $ECHO_N "checking route read method check... $ECHO_C" >&6 +if test "${zebra_rtread+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$netlink" = yes; then + RTREAD_METHOD="rtread_netlink.o" + zebra_rtread="netlink" +else +for zebra_rtread in /proc/net/route /dev/ip /dev/null; +do + test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break +done +case $zebra_rtread in + "/proc/net/route") RTREAD_METHOD="rtread_proc.o" + zebra_rtread="proc";; + "/dev/ip") RTREAD_METHOD="rtread_getmsg.o" + zebra_rtread="getmsg";; + *) RTREAD_METHOD="rtread_sysctl.o" + zebra_rtread="sysctl";; +esac +fi +fi +echo "$as_me:$LINENO: result: $zebra_rtread" >&5 +echo "${ECHO_T}$zebra_rtread" >&6 + + +echo "$as_me:$LINENO: checking interface looking up method" >&5 +echo $ECHO_N "checking interface looking up method... $ECHO_C" >&6 +if test "$netlink" = yes; then + echo "$as_me:$LINENO: result: netlink" >&5 +echo "${ECHO_T}netlink" >&6 + IF_METHOD=if_netlink.o +else + if test "$opsys" = "sol2-6";then + echo "$as_me:$LINENO: result: solaris" >&5 +echo "${ECHO_T}solaris" >&6 + IF_METHOD=if_ioctl.o + elif test "$opsys" = "openbsd";then + echo "$as_me:$LINENO: result: openbsd" >&5 +echo "${ECHO_T}openbsd" >&6 + IF_METHOD=if_ioctl.o + elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: sysctl" >&5 +echo "${ECHO_T}sysctl" >&6 + IF_METHOD=if_sysctl.o + cat >>confdefs.h <<\_ACEOF +#define HAVE_NET_RT_IFLIST 1 +_ACEOF + + else + echo "$as_me:$LINENO: result: ioctl" >&5 +echo "${ECHO_T}ioctl" >&6 + IF_METHOD=if_ioctl.o + fi +fi + + +if test -r /proc/net/dev; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_PROC_NET_DEV 1 +_ACEOF + + IF_PROC=if_proc.o +fi + +if test -r /proc/net/if_inet6; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_PROC_NET_IF_INET6 1 +_ACEOF + + IF_PROC=if_proc.o +fi + + +echo "$as_me:$LINENO: checking ipforward method check" >&5 +echo $ECHO_N "checking ipforward method check... $ECHO_C" >&6 +if test "${zebra_ipforward_path+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null; +do + test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break +done +case $zebra_ipforward_path in + "/proc/net/snmp") IPFORWARD=ipforward_proc.o + zebra_ipforward_path="proc";; + "/dev/ip") + case "$host" in + *-nec-sysv4*) IPFORWARD=ipforward_ews.o + zebra_ipforward_path="ews";; + *) IPFORWARD=ipforward_solaris.o + zebra_ipforward_path="solaris";; + esac;; + *) IPFORWARD=ipforward_sysctl.o + zebra_ipforward_path="sysctl";; +esac +fi +echo "$as_me:$LINENO: result: $zebra_ipforward_path" >&5 +echo "${ECHO_T}$zebra_ipforward_path" >&6 + + + +for ac_func in getaddrinfo +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + have_getaddrinfo=yes +else + have_getaddrinfo=no +fi +done + + +echo "$as_me:$LINENO: checking whether does this OS have IPv6 stack" >&5 +echo $ECHO_N "checking whether does this OS have IPv6 stack... $ECHO_C" >&6 +if test "${enable_ipv6}" = "no"; then + echo "$as_me:$LINENO: result: disabled" >&5 +echo "${ECHO_T}disabled" >&6 +else +if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define INRIA_IPV6 1 +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + LIB_IPV6="" + echo "$as_me:$LINENO: result: INRIA IPv6" >&5 +echo "${ECHO_T}INRIA IPv6" >&6 +fi +if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define KAME 1 +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then + LIB_IPV6="-L/usr/local/v6/lib -linet6" + fi + echo "$as_me:$LINENO: result: KAME" >&5 +echo "${ECHO_T}KAME" >&6 +fi +if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define NRL 1 +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test x"$opsys" = x"bsdi";then + cat >>confdefs.h <<\_ACEOF +#define BSDI_NRL 1 +_ACEOF + + echo "$as_me:$LINENO: result: BSDI_NRL" >&5 +echo "${ECHO_T}BSDI_NRL" >&6 + else + echo "$as_me:$LINENO: result: NRL" >&5 +echo "${ECHO_T}NRL" >&6 + fi +fi + +if test "${enable_ipv6}" = "yes"; then + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + #include <linux/version.h> + /* 2.1.128 or later */ + #if LINUX_VERSION_CODE >= 0x020180 + yes + #endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;echo "$as_me:$LINENO: result: Linux IPv6" >&5 +echo "${ECHO_T}Linux IPv6" >&6 +fi +rm -f conftest* + +else + if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" + then + zebra_cv_ipv6=yes + zebra_cv_linux_ipv6=yes + echo "$as_me:$LINENO: result: Linux IPv6" >&5 +echo "${ECHO_T}Linux IPv6" >&6 + fi +fi + +if test "$zebra_cv_linux_ipv6" = "yes";then + cat >>confdefs.h <<\_ACEOF +#define HAVE_IPV6 1 +_ACEOF + + echo "$as_me:$LINENO: checking for GNU libc 2.1" >&5 +echo $ECHO_N "checking for GNU libc 2.1... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#include <features.h> +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + yes +#endif +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + glibc=yes; echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + cat >>confdefs.h <<\_ACEOF +#define LINUX_IPV6 1 +_ACEOF + + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test "$glibc" != "yes"; then + INCLUDES="-I/usr/inet6/include" + if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then + LIB_IPV6="-L/usr/inet6/lib -linet6" + fi + fi +fi + +LIBS="$LIB_IPV6 $LIBS" + + +if test x"$RIPNGD" = x""; then + echo "$as_me:$LINENO: result: IPv4 only" >&5 +echo "${ECHO_T}IPv4 only" >&6 +fi +fi + +if test "${enable_zebra}" = "no";then + ZEBRA="" +else + ZEBRA="zebra" +fi + +if test "${enable_bgpd}" = "no";then + BGPD="" +else + BGPD="bgpd" +fi + +if test "${enable_ripd}" = "no";then + RIPD="" +else + RIPD="ripd" +fi + +if test "${enable_ospfd}" = "no";then + OSPFD="" +else + OSPFD="ospfd" +fi + +case "${enable_ripngd}" in + "yes") RIPNGD="ripngd";; + "no" ) RIPNGD="";; + * ) ;; +esac + +case "${enable_ospf6d}" in + "yes") OSPF6D="ospf6d";; + "no" ) OSPF6D="";; + * ) ;; +esac + +case "${enable_isisd}" in + "yes") ISISD="isisd";; + "no" ) ISISD="";; + * ) ;; +esac + +if test "${enable_bgp_announce}" = "no";then + cat >>confdefs.h <<\_ACEOF +#define DISABLE_BGP_ANNOUNCE 1 +_ACEOF + +fi + + + + + + + + + + + +echo "$as_me:$LINENO: checking for inet_ntop in -lc" >&5 +echo $ECHO_N "checking for inet_ntop in -lc... $ECHO_C" >&6 +if test "${ac_cv_lib_c_inet_ntop+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char inet_ntop (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +inet_ntop (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_c_inet_ntop=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_c_inet_ntop=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_ntop" >&5 +echo "${ECHO_T}$ac_cv_lib_c_inet_ntop" >&6 +if test $ac_cv_lib_c_inet_ntop = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_NTOP 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for inet_pton in -lc" >&5 +echo $ECHO_N "checking for inet_pton in -lc... $ECHO_C" >&6 +if test "${ac_cv_lib_c_inet_pton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char inet_pton (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +inet_pton (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_c_inet_pton=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_c_inet_pton=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_c_inet_pton" >&5 +echo "${ECHO_T}$ac_cv_lib_c_inet_pton" >&6 +if test $ac_cv_lib_c_inet_pton = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_PTON 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5 +echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6 +if test "${ac_cv_lib_crypt_crypt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypt $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +crypt (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypt_crypt=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_crypt_crypt=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5 +echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6 +if test $ac_cv_lib_crypt_crypt = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPT 1 +_ACEOF + + LIBS="-lcrypt $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for res_init in -lresolv" >&5 +echo $ECHO_N "checking for res_init in -lresolv... $ECHO_C" >&6 +if test "${ac_cv_lib_resolv_res_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char res_init (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +res_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_resolv_res_init=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_resolv_res_init=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_init" >&5 +echo "${ECHO_T}$ac_cv_lib_resolv_res_init" >&6 +if test $ac_cv_lib_resolv_res_init = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRESOLV 1 +_ACEOF + + LIBS="-lresolv $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for main in -lm" >&5 +echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_m_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5 +echo "${ECHO_T}$ac_cv_lib_m_main" >&6 +if test $ac_cv_lib_m_main = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBM 1 +_ACEOF + + LIBS="-lm $LIBS" + +fi + + +echo "$as_me:$LINENO: checking for __inet_ntop" >&5 +echo $ECHO_N "checking for __inet_ntop... $ECHO_C" >&6 +if test "${ac_cv_func___inet_ntop+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char __inet_ntop (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __inet_ntop (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___inet_ntop) || defined (__stub_____inet_ntop) +choke me +#else +f = __inet_ntop; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func___inet_ntop=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_func___inet_ntop=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func___inet_ntop" >&5 +echo "${ECHO_T}$ac_cv_func___inet_ntop" >&6 +if test $ac_cv_func___inet_ntop = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_NTOP 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for __inet_pton" >&5 +echo $ECHO_N "checking for __inet_pton... $ECHO_C" >&6 +if test "${ac_cv_func___inet_pton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char __inet_pton (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __inet_pton (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___inet_pton) || defined (__stub_____inet_pton) +choke me +#else +f = __inet_pton; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func___inet_pton=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_func___inet_pton=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func___inet_pton" >&5 +echo "${ECHO_T}$ac_cv_func___inet_pton" >&6 +if test $ac_cv_func___inet_pton = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_PTON 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for __inet_aton" >&5 +echo $ECHO_N "checking for __inet_aton... $ECHO_C" >&6 +if test "${ac_cv_func___inet_aton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char __inet_aton (); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char __inet_aton (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub___inet_aton) || defined (__stub_____inet_aton) +choke me +#else +f = __inet_aton; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func___inet_aton=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_func___inet_aton=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func___inet_aton" >&5 +echo "${ECHO_T}$ac_cv_func___inet_aton" >&6 +if test $ac_cv_func___inet_aton = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_INET_ATON 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking for regexec in -lc" >&5 +echo $ECHO_N "checking for regexec in -lc... $ECHO_C" >&6 +if test "${ac_cv_lib_c_regexec+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char regexec (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +regexec (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_c_regexec=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_c_regexec=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_c_regexec" >&5 +echo "${ECHO_T}$ac_cv_lib_c_regexec" >&6 +if test $ac_cv_lib_c_regexec = yes; then + cat >>confdefs.h <<\_ACEOF +#define HAVE_GNU_REGEX 1 +_ACEOF + + LIB_REGEX="" +else + LIB_REGEX="regex.o" +fi + + + + +if test "${enable_snmp}" = "yes";then + old_libs="${LIBS}" + LIBS="-L/usr/local/lib" + unset ac_cv_lib_snmp_asn_parse_int + echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnmp $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_snmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_snmp_asn_parse_int=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6 +if test $ac_cv_lib_snmp_asn_parse_int = yes; then + HAVE_SNMP=yes +fi + + if test "${HAVE_SNMP}" = ""; then + unset ac_cv_lib_snmp_asn_parse_int + echo "$as_me:$LINENO: checking for main in -lcrypto" >&5 +echo $ECHO_N "checking for main in -lcrypto... $ECHO_C" >&6 +if test "${ac_cv_lib_crypto_main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_crypto_main=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_crypto_main=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_crypto_main" >&5 +echo "${ECHO_T}$ac_cv_lib_crypto_main" >&6 +if test $ac_cv_lib_crypto_main = yes; then + NEED_CRYPTO=yes +fi + + if test "${NEED_CRYPTO}" = ""; then + echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnmp $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_snmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_snmp_asn_parse_int=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6 +if test $ac_cv_lib_snmp_asn_parse_int = yes; then + HAVE_SNMP=yes; NEED_CRYPTO=yes +fi + + else + echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnmp "-lcrypto" $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_snmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_snmp_asn_parse_int=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6 +if test $ac_cv_lib_snmp_asn_parse_int = yes; then + HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" +fi + + fi + fi + LIBS="${old_libs}" + + if test "${HAVE_SNMP}" = ""; then + old_libs="${LIBS}" + LIBS="-L/usr/local/lib" + echo "$as_me:$LINENO: checking for asn_parse_int in -lsnmp" >&5 +echo $ECHO_N "checking for asn_parse_int in -lsnmp... $ECHO_C" >&6 +if test "${ac_cv_lib_snmp_asn_parse_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsnmp $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char asn_parse_int (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +asn_parse_int (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_snmp_asn_parse_int=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_snmp_asn_parse_int=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_snmp_asn_parse_int" >&5 +echo "${ECHO_T}$ac_cv_lib_snmp_asn_parse_int" >&6 +if test $ac_cv_lib_snmp_asn_parse_int = yes; then + HAVE_SNMP=yes +fi + + LIBS="${old_libs}" + fi + if test "${HAVE_SNMP}" = "yes"; then + for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null + do + test -f "${ac_snmp}" && break + done + case ${ac_snmp} in + /usr/include/ucd-snmp/*) + cat >>confdefs.h <<\_ACEOF +#define HAVE_SNMP 1 +_ACEOF + + CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp" + LIBS="${LIBS} -lsnmp" + ;; + /usr/local/include/ucd-snmp/*) + cat >>confdefs.h <<\_ACEOF +#define HAVE_SNMP 1 +_ACEOF + + CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp" + LIBS="${LIBS} -L/usr/local/lib -lsnmp" + ;; + esac + if test "${NEED_CRYPTO}" = "yes"; then + LIBS="${LIBS} -lcrypto" + fi + fi +fi + +echo "$as_me:$LINENO: checking whether struct sockaddr has a sa_len field" >&5 +echo $ECHO_N "checking whether struct sockaddr has a sa_len field... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/socket.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SA_LEN 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether struct sockaddr_in has a sin_len field" >&5 +echo $ECHO_N "checking whether struct sockaddr_in has a sin_len field... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <netinet/in.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SIN_LEN 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether struct sockaddr_un has a sun_len field" >&5 +echo $ECHO_N "checking whether struct sockaddr_un has a sun_len field... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/un.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SUN_LEN 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +if test "$zebra_cv_ipv6" = yes; then + echo "$as_me:$LINENO: checking whether struct sockaddr_in6 has a sin6_scope_id field" >&5 +echo $ECHO_N "checking whether struct sockaddr_in6 has a sin6_scope_id field... $ECHO_C" >&6 + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <netinet/in.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SIN6_SCOPE_ID 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi + +echo "$as_me:$LINENO: checking whther socklen_t is defined" >&5 +echo $ECHO_N "checking whther socklen_t is defined... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +socklen_t ac_x; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKLEN_T 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether struct sockaddr_dl exist" >&5 +echo $ECHO_N "checking whether struct sockaddr_dl exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <net/if_dl.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "sockaddr_dl" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKADDR_DL 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct ifaliasreq exist" >&5 +echo $ECHO_N "checking whether struct ifaliasreq exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <net/if.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ifaliasreq" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_IFALIASREQ 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct if6_aliasreq exist" >&5 +echo $ECHO_N "checking whether struct if6_aliasreq exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <netinet6/in6_var.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "in6_aliasreq" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_IN6_ALIASREQ 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct rt_addrinfo exist" >&5 +echo $ECHO_N "checking whether struct rt_addrinfo exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <net/route.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "rt_addrinfo" >/dev/null 2>&1; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_RT_ADDRINFO 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest* + + +echo "$as_me:$LINENO: checking whether struct in_pktinfo exist" >&5 +echo $ECHO_N "checking whether struct in_pktinfo exist... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <netinet/in.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +struct in_pktinfo ac_x; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_INPKTINFO 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +echo "$as_me:$LINENO: checking whether getrusage is available" >&5 +echo $ECHO_N "checking whether getrusage is available... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#include <sys/resource.h> + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + cat >>confdefs.h <<\_ACEOF +#define HAVE_RUSAGE 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +file="${srcdir}/lib/version.h" +VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file` + + +echo "$as_me:$LINENO: checking pid file directory" >&5 +echo $ECHO_N "checking pid file directory... $ECHO_C" >&6 +if test "${ac_piddir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + for ZEBRA_PID_DIR in /var/run /var/adm /etc /dev/null; +do + test -d $ZEBRA_PID_DIR && break +done +ac_piddir=$ZEBRA_PID_DIR +if test $ZEBRA_PID_DIR = "/dev/null"; then + echo "PID DIRECTORY NOT FOUND!" +fi +fi +echo "$as_me:$LINENO: result: $ac_piddir" >&5 +echo "${ECHO_T}$ac_piddir" >&6 +cat >>confdefs.h <<_ACEOF +#define PATH_ZEBRA_PID "$ac_piddir/zebra.pid" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PATH_RIPD_PID "$ac_piddir/ripd.pid" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PATH_RIPNGD_PID "$ac_piddir/ripngd.pid" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PATH_BGPD_PID "$ac_piddir/bgpd.pid" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PATH_OSPFD_PID "$ac_piddir/ospfd.pid" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PATH_OSPF6D_PID "$ac_piddir/ospf6d.pid" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PATH_ISISD_PID "$ac_piddir/isisd.pid" +_ACEOF + + +echo "$as_me:$LINENO: checking for working htonl" >&5 +echo $ECHO_N "checking for working htonl... $ECHO_C" >&6 +if test "${ac_cv_htonl_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +htonl (0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_htonl_works=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_htonl_works=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi + +echo "$as_me:$LINENO: result: $ac_cv_htonl_works" >&5 +echo "${ECHO_T}$ac_cv_htonl_works" >&6 + +ac_config_files="$ac_config_files Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overriden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if cmp -s $cache_file confcache; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# NLS nuisances. +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + +(set +x; test -n "`(LANG=C; export LANG) 2>&1`") && + { $as_unset LANG || test "${LANG+set}" != set; } || + { LANG=C; export LANG; } +(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") && + { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } || + { LC_ALL=C; export LC_ALL; } +(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") && + { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } || + { LC_TIME=C; export LC_TIME; } +(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") && + { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } || + { LC_CTYPE=C; export LC_CTYPE; } +(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") && + { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } || + { LANGUAGE=C; export LANGUAGE; } +(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") && + { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } || + { LC_COLLATE=C; export LC_COLLATE; } +(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") && + { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } || + { LC_NUMERIC=C; export LC_NUMERIC; } +(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") && + { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } || + { LC_MESSAGES=C; export LC_MESSAGES; } + + +# Name of the executable. +as_me=`(basename "$0") 2>/dev/null || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conftest.sh + echo "exit 0" >>conftest.sh + chmod +x conftest.sh + if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conftest.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="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="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; } + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by $as_me, which was +generated by GNU Autoconf 2.53. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -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 <bug-autoconf@gnu.org>." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.53, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + shift + set dummy "$ac_option" "$ac_optarg" ${1+"$@"} + shift + ;; + -*);; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_need_defaults=false;; + esac + + case $1 in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion" + exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;; +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + shift + CONFIG_FILES="$CONFIG_FILES $1" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + shift + CONFIG_HEADERS="$CONFIG_HEADERS $1" + ac_need_defaults=false;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + "zebra/Makefile" ) CONFIG_FILES="$CONFIG_FILES zebra/Makefile" ;; + "ripd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripd/Makefile" ;; + "ripngd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ripngd/Makefile" ;; + "bgpd/Makefile" ) CONFIG_FILES="$CONFIG_FILES bgpd/Makefile" ;; + "ospfd/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospfd/Makefile" ;; + "ospf6d/Makefile" ) CONFIG_FILES="$CONFIG_FILES ospf6d/Makefile" ;; + "isisd/Makefile" ) CONFIG_FILES="$CONFIG_FILES isisd/Makefile" ;; + "vtysh/Makefile" ) CONFIG_FILES="$CONFIG_FILES vtysh/Makefile" ;; + "doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/cs$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@CPP@,$CPP,;t t +s,@AR@,$AR,;t t +s,@ac_ct_AR@,$ac_ct_AR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@MULTIPATH_NUM@,$MULTIPATH_NUM,;t t +s,@LIBPAM@,$LIBPAM,;t t +s,@RT_METHOD@,$RT_METHOD,;t t +s,@KERNEL_METHOD@,$KERNEL_METHOD,;t t +s,@OTHER_METHOD@,$OTHER_METHOD,;t t +s,@RTREAD_METHOD@,$RTREAD_METHOD,;t t +s,@IF_METHOD@,$IF_METHOD,;t t +s,@IF_PROC@,$IF_PROC,;t t +s,@IPFORWARD@,$IPFORWARD,;t t +s,@LIB_IPV6@,$LIB_IPV6,;t t +s,@ZEBRA@,$ZEBRA,;t t +s,@BGPD@,$BGPD,;t t +s,@RIPD@,$RIPD,;t t +s,@RIPNGD@,$RIPNGD,;t t +s,@OSPFD@,$OSPFD,;t t +s,@OSPF6D@,$OSPF6D,;t t +s,@ISISD@,$ISISD,;t t +s,@VTYSH@,$VTYSH,;t t +s,@INCLUDES@,$INCLUDES,;t t +s,@CURSES@,$CURSES,;t t +s,@LIB_REGEX@,$LIB_REGEX,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || + mkdir "$as_incr_dir" || + { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; } + ;; + esac +done; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # egrep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { case "$ac_dir" in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy="$ac_dir" +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || + mkdir "$as_incr_dir" || + { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; } + ;; + esac +done; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi + # Run the commands associated with the file. + case $ac_file in + config.h ) # update the timestamp +echo 'timestamp for config.h' >"./stamp-h1" + ;; + esac +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { case $dirpart/$fdir in + [\\/]* | ?:[\\/]* ) as_incr_dir=;; + *) as_incr_dir=.;; +esac +as_dummy=$dirpart/$fdir +for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do + case $as_mkdir_dir in + # Skip DOS drivespec + ?:) as_incr_dir=$as_mkdir_dir ;; + *) + as_incr_dir=$as_incr_dir/$as_mkdir_dir + test -d "$as_incr_dir" || + mkdir "$as_incr_dir" || + { { echo "$as_me:$LINENO: error: cannot create $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; } + ;; + esac +done; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + exec 5>/dev/null + $SHELL $CONFIG_STATUS || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + + +echo " +zebra configuration +------------------- +zebra version : ${VERSION} +host operationg system : ${host_os} +source code location : ${srcdir} +compiler : ${CC} +compiler flags : ${CFLAGS} +directory for pid files : ${ac_piddir} +" diff --git a/isisd/modified/configure.in b/isisd/modified/configure.in new file mode 100755 index 00000000..49b508bc --- /dev/null +++ b/isisd/modified/configure.in @@ -0,0 +1,882 @@ +## +## Configure template file for Zebra. +## autoconf will generate configure script. +## +## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org> +## +AC_PREREQ(2.13) + +AC_INIT(lib/zebra.h) +AM_INIT_AUTOMAKE(zebra, 0.93) +AM_CONFIG_HEADER(config.h) + +dnl ----------------------------------- +dnl Get hostname and other information. +dnl ----------------------------------- +AC_CANONICAL_HOST + +dnl ------------ +dnl Check CFLAGS +dnl ------------ +AC_ARG_WITH(cflags, +[ --with-cflags Set CFLAGS for use in compilation.]) +if test "x$with_cflags" != "x" ; then + CFLAGS="$with_cflags" ; cflags_specified=yes ; +elif test -n "$CFLAGS" ; then + cflags_specified=yes ; +fi + +dnl -------- +dnl Check CC +dnl -------- +AC_PROG_CC + +dnl ----------------------------------------- +dnl If CLFAGS doesn\'t exist set default value +dnl ----------------------------------------- +if test "x$cflags_specified" = "x" ; then + CFLAGS="$CFLAGS -Wall" +fi + +dnl -------------- +dnl Check programs +dnl -------------- +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(RANLIB, ranlib, :) + +dnl --------- +dnl AIX check +dnl --------- +AC_AIX + +dnl ---------------------- +dnl Packages configuration +dnl ---------------------- +AC_ARG_ENABLE(vtysh, +[ --enable-vtysh, Make integrated VTY version of zebra]) +AC_ARG_ENABLE(ipv6, +[ --disable-ipv6 turn off IPv6 related features and daemons]) +AC_ARG_ENABLE(zebra, +[ --disable-zebra do not build zebra daemon]) +AC_ARG_ENABLE(bgpd, +[ --disable-bgpd do not build bgpd]) +AC_ARG_ENABLE(ripd, +[ --disable-ripd do not build ripd]) +AC_ARG_ENABLE(ripngd, +[ --disable-ripngd do not build ripngd]) +AC_ARG_ENABLE(ospfd, +[ --disable-ospfd do not build ospfd]) +AC_ARG_ENABLE(ospf6d, +[ --disable-ospf6d do not build ospf6d]) +AC_ARG_ENABLE(isisd, +[ --disable-isisd do not build isisd]) +AC_ARG_ENABLE(bgp-announce, +[ --disable-bgp-announce, turn off BGP route announcement]) +AC_ARG_ENABLE(netlink, +[ --enable-netlink force to use Linux netlink interface]) +AC_ARG_ENABLE(broken-aliases, +[ --enable-broken-aliases enable aliases as distinct interfaces for Linux 2.2.X]) +AC_ARG_ENABLE(snmp, +[ --enable-snmp enable SNMP support]) +AC_ARG_WITH(libpam, +[ --with-libpam use libpam for PAM support in vtysh]) +AC_ARG_ENABLE(tcpsock, +[ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon]) +dnl Temporary option until OSPF NSSA implementation complete +AC_ARG_ENABLE(nssa, +[ --enable-nssa enable OSPF NSSA option]) +AC_ARG_ENABLE(opaque-lsa, +[ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)]) +AC_ARG_ENABLE(ospf-te, +[ --enable-ospf-te enable Traffic Engineering Extension to OSPF]) +AC_ARG_ENABLE(multipath, +[ --enable-multipath=ARG enable multipath function, ARG must be digit]) + +dnl AC_ARG_ENABLE(rtadv, +dnl [ --enable-rtadv enable IPV6 router advertisment option]) + +if test "${enable_broken_aliases}" = "yes"; then + if test "${enable_netlink}" = "yes" + then + echo "Sorry, you can't use netlink with broken aliases" + exit 1 + fi + AC_DEFINE(HAVE_BROKEN_ALIASES) + enable_netlink=no +fi + +if test "${enable_tcp_zebra}" = "yes"; then + AC_DEFINE(HAVE_TCP_ZEBRA) +fi + +if test "${enable_nssa}" = "yes"; then + AC_DEFINE(HAVE_NSSA) +fi + +if test "${enable_opaque_lsa}" = "yes"; then + AC_DEFINE(HAVE_OPAQUE_LSA) +fi + +if test "${enable_ospf_te}" = "yes"; then + AC_DEFINE(HAVE_OPAQUE_LSA) + AC_DEFINE(HAVE_OSPF_TE) +fi + +dnl if test "${enable_rtadv}" = "yes"; then +dnl AC_DEFINE(HAVE_RTADV) +dnl fi + +changequote(, )dnl + +MULTIPATH_NUM=1 + +case "${enable_multipath}" in + [0-9]|[1-9][0-9]) + MULTIPATH_NUM="${enable_multipath}" + ;; + "") + ;; + *) + echo "Please specify digit to --enable-multipath ARG." + exit 1 + ;; +esac + +changequote([, ])dnl + +AC_SUBST(MULTIPATH_NUM) + +dnl ------------------- +dnl Check header files. +dnl ------------------- +AC_STDC_HEADERS +AC_CHECK_HEADERS(string.h stropts.h sys/conf.h sys/ksym.h sys/time.h sys/times.h sys/select.h sys/sysctl.h sys/sockio.h sys/types.h net/if_dl.h net/if_var.h linux/version.h kvm.h netdb.h netinet/in.h net/netopt.h netinet/in_var.h netinet/in6_var.h netinet/in6.h inet/nd.h asm/types.h netinet/icmp6.h netinet6/nd6.h libutil.h) + +dnl check some types +AC_C_CONST +dnl AC_TYPE_PID_T +AC_TYPE_SIGNAL + +dnl Some systems (Solaris 2.x) require libnsl (Network Services Library) +case "$host" in + *-sunos5.6* | *-solaris2.6*) + opsys=sol2-6 + AC_DEFINE(SUNOS_5) + AC_CHECK_LIB(xnet, main) + CURSES=-lcurses + ;; + *-sunos5* | *-solaris2*) + AC_DEFINE(SUNOS_5) + AC_CHECK_LIB(socket, main) + AC_CHECK_LIB(nsl, main) + CURSES=-lcurses + ;; + *-linux-*) + opsys=gnu-linux + AC_DEFINE(GNU_LINUX) + ;; + *-nec-sysv4*) + AC_CHECK_LIB(nsl, gethostbyname) + AC_CHECK_LIB(socket, socket) + ;; + *-freebsd3.2) + AC_DEFINE(FREEBSD_32) + ;; + *-openbsd*) + opsys=openbsd + AC_DEFINE(OPEN_BSD) + ;; + *-bsdi*) + opsys=bsdi + OTHER_METHOD="mtu_kvm.o" + AC_CHECK_LIB(kvm, main) + ;; +esac + +case "${host_cpu}-${host_os}" in + i?86-solaris*) + AC_DEFINE(SOLARIS_X86) + ;; +esac + +dnl --------------------- +dnl Integrated VTY option +dnl --------------------- +case "${enable_vtysh}" in + "yes") VTYSH="vtysh"; + AC_DEFINE(VTYSH) + AC_CHECK_LIB(tinfo, tputs, , AC_CHECK_LIB(ncurses, tputs)) + AC_CHECK_LIB(readline, main) + if test $ac_cv_lib_readline_main = no; then + AC_MSG_ERROR([vtysh needs libreadline but was not found on your system.]) + fi + AC_CHECK_HEADER(readline/history.h) + if test $ac_cv_header_readline_history_h = no;then + AC_MSG_ERROR([readline is too old to have readline/history.h, please update to the latest readline library.]) + fi + ;; + "no" ) VTYSH="";; + * ) ;; +esac + +dnl ---------- +dnl PAM module +dnl ---------- +if test "$with_libpam" = "yes"; then +dnl took this test from proftpd's configure.in and suited to our needs +dnl ------------------------------------------------------------------------- +dnl +dnl This next check looks funky due to a linker problem with some versions +dnl of the PAM library. Prior to 0.72 release, the Linux PAM shared library +dnl omitted requiring libdl linking information. PAM-0.72 or better ships +dnl with RedHat 6.2 and Debian 2.2 or better. +AC_CHECK_LIB(pam, pam_start, + [AC_CHECK_LIB(pam, misc_conv, + [AC_DEFINE(USE_PAM) + LIBPAM="-lpam"], + [AC_DEFINE(USE_PAM) + LIBPAM="-lpam -lpam_misc"] + ) + ], + + [AC_CHECK_LIB(pam, pam_end, + [AC_CHECK_LIB(pam, misc_conv, + [AC_DEFINE(USE_PAM) + LIBPAM="-lpam -ldl"], + [AC_DEFINE(USE_PAM) + LIBPAM="-lpam -ldl -lpam_misc"] + ) + ],AC_MSG_WARN([*** pam support will not be built ***]), + [-ldl]) + ] +) +fi +AC_SUBST(LIBPAM) + +dnl ------------------------------- +dnl Endian-ness check +dnl ------------------------------- +AC_DEFUN(ZEBRA_AC_C_BIGENDIAN, +[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian, +[ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/param.h>], [ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif], [# It does; now see whether it defined to BIG_ENDIAN or not. +AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/param.h>], [ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)]) +if test $ac_cv_c_bigendian = unknown; then +AC_TRY_RUN([main () { + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no) +fi]) +if test $ac_cv_c_bigendian = yes; then + AC_DEFINE(WORDS_BIGENDIAN,1,Big endian words) +fi +]) + +dnl ------------------------------- +dnl check the size in byte of the C +dnl ------------------------------- +dnl AC_CHECK_SIZEOF(char) +dnl AC_CHECK_SIZEOF(int) +dnl AC_CHECK_SIZEOF(short) +dnl AC_CHECK_SIZEOF(long) + +dnl ---------------------------- +dnl check existance of functions +dnl ---------------------------- +AC_CHECK_FUNCS(bcopy bzero strerror inet_aton daemon snprintf vsnprintf strlcat strlcpy if_nametoindex if_indextoname getifaddrs) +AC_CHECK_FUNCS(setproctitle, ,[AC_CHECK_LIB(util, setproctitle, [LIBS="$LIBS -lutil"; AC_DEFINE(HAVE_SETPROCTITLE)])]) + +dnl ------------------------------------ +dnl Determine routing get and set method +dnl ------------------------------------ +AC_MSG_CHECKING(zebra between kernel interface method) +if test x"$opsys" = x"gnu-linux"; then + if test "${enable_netlink}" = "yes";then + AC_MSG_RESULT(netlink) + RT_METHOD=rt_netlink.o + AC_DEFINE(HAVE_NETLINK) + netlink=yes + elif test "${enable_netlink}" = "no"; then + AC_MSG_RESULT(ioctl) + RT_METHOD=rt_ioctl.o + netlink=no + else + AC_EGREP_CPP(yes, + [#include <linux/autoconf.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE > 131328 /* 2.1.0 or later */ +#ifdef CONFIG_RTNETLINK + yes +#endif +#endif +#if LINUX_VERSION_CODE > 132112 /* 2.4.17 or later */ + yes +#endif + ], + [AC_MSG_RESULT(netlink) + RT_METHOD=rt_netlink.o + AC_DEFINE(HAVE_NETLINK) + netlink=yes], + [AC_MSG_RESULT(ioctl) + RT_METHOD=rt_ioctl.o]) + fi +else + if test "$opsys" = "sol2-6";then + AC_MSG_RESULT(solaris) + KERNEL_METHOD="kernel_socket.o" + RT_METHOD="rt_socket.o" + else + AC_TRY_RUN([#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> + +main () +{ + int ac_sock; + + ac_sock = socket (AF_ROUTE, SOCK_RAW, 0); + if (ac_sock < 0 && errno == EINVAL) + exit (1); + exit (0); +}], + [AC_DEFINE(HAVE_AF_ROUTE) + KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + AC_MSG_RESULT(socket)], + [RT_METHOD=rt_ioctl.o + AC_MSG_RESULT(ioctl)], + [KERNEL_METHOD=kernel_socket.o + RT_METHOD=rt_socket.o + AC_MSG_RESULT(socket)]) + fi +fi +AC_SUBST(RT_METHOD) +AC_SUBST(KERNEL_METHOD) +AC_SUBST(OTHER_METHOD) + +dnl ------------------------------ +dnl check kernel route read method +dnl ------------------------------ +AC_CACHE_CHECK(route read method check, zebra_rtread, +[if test "$netlink" = yes; then + RTREAD_METHOD="rtread_netlink.o" + zebra_rtread="netlink" +else +for zebra_rtread in /proc/net/route /dev/ip /dev/null; +do + test x`ls $zebra_rtread 2>/dev/null` = x"$zebra_rtread" && break +done +case $zebra_rtread in + "/proc/net/route") RTREAD_METHOD="rtread_proc.o" + zebra_rtread="proc";; + "/dev/ip") RTREAD_METHOD="rtread_getmsg.o" + zebra_rtread="getmsg";; + *) RTREAD_METHOD="rtread_sysctl.o" + zebra_rtread="sysctl";; +esac +fi]) +AC_SUBST(RTREAD_METHOD) + +dnl ----------------------------- +dnl check interface lookup method +dnl ----------------------------- +AC_MSG_CHECKING(interface looking up method) +if test "$netlink" = yes; then + AC_MSG_RESULT(netlink) + IF_METHOD=if_netlink.o +else + if test "$opsys" = "sol2-6";then + AC_MSG_RESULT(solaris) + IF_METHOD=if_ioctl.o + elif test "$opsys" = "openbsd";then + AC_MSG_RESULT(openbsd) + IF_METHOD=if_ioctl.o + elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then + AC_MSG_RESULT(sysctl) + IF_METHOD=if_sysctl.o + AC_DEFINE(HAVE_NET_RT_IFLIST) + else + AC_MSG_RESULT(ioctl) + IF_METHOD=if_ioctl.o + fi +fi +AC_SUBST(IF_METHOD) + +dnl ----------------------- +dnl check proc file system. +dnl ----------------------- +if test -r /proc/net/dev; then + AC_DEFINE(HAVE_PROC_NET_DEV) + IF_PROC=if_proc.o +fi + +if test -r /proc/net/if_inet6; then + AC_DEFINE(HAVE_PROC_NET_IF_INET6) + IF_PROC=if_proc.o +fi +AC_SUBST(IF_PROC) + +dnl ----------------------------- +dnl check ipforward detect method +dnl ----------------------------- +AC_CACHE_CHECK(ipforward method check, zebra_ipforward_path, +[for zebra_ipforward_path in /proc/net/snmp /dev/ip /dev/null; +do + test x`ls $zebra_ipforward_path 2>/dev/null` = x"$zebra_ipforward_path" && break +done +case $zebra_ipforward_path in + "/proc/net/snmp") IPFORWARD=ipforward_proc.o + zebra_ipforward_path="proc";; + "/dev/ip") + case "$host" in + *-nec-sysv4*) IPFORWARD=ipforward_ews.o + zebra_ipforward_path="ews";; + *) IPFORWARD=ipforward_solaris.o + zebra_ipforward_path="solaris";; + esac;; + *) IPFORWARD=ipforward_sysctl.o + zebra_ipforward_path="sysctl";; +esac]) +AC_SUBST(IPFORWARD) + +AC_CHECK_FUNCS(getaddrinfo, [have_getaddrinfo=yes], [have_getaddrinfo=no]) + +dnl ---------- +dnl IPv6 check +dnl ---------- +AC_MSG_CHECKING(whether does this OS have IPv6 stack) +if test "${enable_ipv6}" = "no"; then + AC_MSG_RESULT(disabled) +else +dnl ---------- +dnl INRIA IPv6 +dnl ---------- +if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + AC_DEFINE(HAVE_IPV6) + AC_DEFINE(INRIA_IPV6) + RIPNGD="ripngd" + OSPF6D="ospf6d" + LIB_IPV6="" + AC_MSG_RESULT(INRIA IPv6) +fi +dnl --------- +dnl KAME IPv6 +dnl --------- +if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + AC_DEFINE(HAVE_IPV6) + AC_DEFINE(KAME) + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then + LIB_IPV6="-L/usr/local/v6/lib -linet6" + fi + AC_MSG_RESULT(KAME) +fi +dnl --------- +dnl NRL check +dnl --------- +if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then + zebra_cv_ipv6=yes + AC_DEFINE(HAVE_IPV6) + AC_DEFINE(NRL) + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test x"$opsys" = x"bsdi";then + AC_DEFINE(BSDI_NRL) + AC_MSG_RESULT(BSDI_NRL) + else + AC_MSG_RESULT(NRL) + fi +fi + +dnl ---------- +dnl Linux IPv6 +dnl ---------- +if test "${enable_ipv6}" = "yes"; then + AC_EGREP_CPP(yes, [ + #include <linux/version.h> + /* 2.1.128 or later */ + #if LINUX_VERSION_CODE >= 0x020180 + yes + #endif], + [zebra_cv_ipv6=yes; zebra_cv_linux_ipv6=yes;AC_MSG_RESULT(Linux IPv6)]) +else + if test x`ls /proc/net/ipv6_route 2>/dev/null` = x"/proc/net/ipv6_route" + then + zebra_cv_ipv6=yes + zebra_cv_linux_ipv6=yes + AC_MSG_RESULT(Linux IPv6) + fi +fi + +if test "$zebra_cv_linux_ipv6" = "yes";then + AC_DEFINE(HAVE_IPV6) + AC_MSG_CHECKING(for GNU libc 2.1) + AC_EGREP_CPP(yes, [ +#include <features.h> +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 + yes +#endif], [glibc=yes; AC_MSG_RESULT(yes)], AC_MSG_RESULT(no)) + AC_DEFINE(LINUX_IPV6) + RIPNGD="ripngd" + OSPF6D="ospf6d" + if test "$glibc" != "yes"; then + INCLUDES="-I/usr/inet6/include" + if test x`ls /usr/inet6/lib/libinet6.a 2>/dev/null` != x;then + LIB_IPV6="-L/usr/inet6/lib -linet6" + fi + fi +fi + +dnl ----------------------- +dnl Set IPv6 related values +dnl ----------------------- +LIBS="$LIB_IPV6 $LIBS" +AC_SUBST(LIB_IPV6) + +if test x"$RIPNGD" = x""; then + AC_MSG_RESULT(IPv4 only) +fi +fi + +dnl -------------------- +dnl Daemon disable check +dnl -------------------- +if test "${enable_zebra}" = "no";then + ZEBRA="" +else + ZEBRA="zebra" +fi + +if test "${enable_bgpd}" = "no";then + BGPD="" +else + BGPD="bgpd" +fi + +if test "${enable_ripd}" = "no";then + RIPD="" +else + RIPD="ripd" +fi + +if test "${enable_ospfd}" = "no";then + OSPFD="" +else + OSPFD="ospfd" +fi + +case "${enable_ripngd}" in + "yes") RIPNGD="ripngd";; + "no" ) RIPNGD="";; + * ) ;; +esac + +case "${enable_ospf6d}" in + "yes") OSPF6D="ospf6d";; + "no" ) OSPF6D="";; + * ) ;; +esac + +case "${enable_isisd}" in + "yes") ISISD="isisd";; + "no" ) ISISD="";; + * ) ;; +esac + +if test "${enable_bgp_announce}" = "no";then + AC_DEFINE(DISABLE_BGP_ANNOUNCE) +fi + +AC_SUBST(ZEBRA) +AC_SUBST(BGPD) +AC_SUBST(RIPD) +AC_SUBST(RIPNGD) +AC_SUBST(OSPFD) +AC_SUBST(OSPF6D) +AC_SUBST(ISISD) +AC_SUBST(VTYSH) +AC_SUBST(INCLUDES) +AC_SUBST(CURSES) +AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP)]) +AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON)]) +AC_CHECK_LIB(crypt, crypt) +AC_CHECK_LIB(resolv, res_init) +AC_CHECK_LIB(m, main) + +dnl --------------------------------------------------- +dnl BSD/OS 4.1 define inet_XtoY function as __inet_XtoY +dnl --------------------------------------------------- +AC_CHECK_FUNC(__inet_ntop, AC_DEFINE(HAVE_INET_NTOP)) +AC_CHECK_FUNC(__inet_pton, AC_DEFINE(HAVE_INET_PTON)) +AC_CHECK_FUNC(__inet_aton, AC_DEFINE(HAVE_INET_ATON)) + +dnl --------------------------- +dnl check system has GNU regexp +dnl --------------------------- +dnl AC_MSG_CHECKING(whether system has GNU regex) +AC_CHECK_LIB(c, regexec, +[AC_DEFINE(HAVE_GNU_REGEX) + LIB_REGEX=""], +[LIB_REGEX="regex.o"]) +AC_SUBST(LIB_REGEX) + +dnl AC_MSG_CHECKING(whether system has GNU regex) +dnl if grep RE_NO_GNU_OPS /usr/include/regex.h >/dev/null 2>&1; then +dnl AC_MSG_RESULT(yes) +dnl AC_DEFINE(HAVE_GNU_REGEX) +dnl LIB_REGEX="" +dnl else +dnl AC_MSG_RESULT(no) +dnl LIB_REGEX="regex.o" +dnl fi +dnl AC_SUBST(LIB_REGEX) + +dnl ------------------ +dnl check SNMP library +dnl ------------------ +if test "${enable_snmp}" = "yes";then +dnl AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) + old_libs="${LIBS}" + LIBS="-L/usr/local/lib" + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, ) + if test "${HAVE_SNMP}" = ""; then + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(crypto, main, [NEED_CRYPTO=yes ], ) + if test "${NEED_CRYPTO}" = ""; then + AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes ],) + else + AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + fi + LIBS="${old_libs}" + + if test "${HAVE_SNMP}" = ""; then + old_libs="${LIBS}" + LIBS="-L/usr/local/lib" + AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) + LIBS="${old_libs}" + fi + if test "${HAVE_SNMP}" = "yes"; then + for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null + do + test -f "${ac_snmp}" && break + done + case ${ac_snmp} in + /usr/include/ucd-snmp/*) + AC_DEFINE(HAVE_SNMP) + CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp" + LIBS="${LIBS} -lsnmp" + ;; + /usr/local/include/ucd-snmp/*) + AC_DEFINE(HAVE_SNMP) + CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp" + LIBS="${LIBS} -L/usr/local/lib -lsnmp" + ;; + esac + if test "${NEED_CRYPTO}" = "yes"; then + LIBS="${LIBS} -lcrypto" + fi + fi +fi + +dnl ---------------------------- +dnl check sa_len of sockaddr +dnl ---------------------------- +AC_MSG_CHECKING(whether struct sockaddr has a sa_len field) +AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/socket.h> +],[static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SA_LEN)], + AC_MSG_RESULT(no)) + +dnl ---------------------------- +dnl check sin_len of sockaddr_in +dnl ---------------------------- +AC_MSG_CHECKING(whether struct sockaddr_in has a sin_len field) +AC_TRY_COMPILE([#include <sys/types.h> +#include <netinet/in.h> +],[static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIN_LEN)], + AC_MSG_RESULT(no)) + +dnl ---------------------------- +dnl check sun_len of sockaddr_un +dnl ---------------------------- +AC_MSG_CHECKING(whether struct sockaddr_un has a sun_len field) +AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/un.h> +],[static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SUN_LEN)], + AC_MSG_RESULT(no)) + +dnl ----------------------------------- +dnl check sin6_scope_id of sockaddr_in6 +dnl ----------------------------------- +if test "$zebra_cv_ipv6" = yes; then + AC_MSG_CHECKING(whether struct sockaddr_in6 has a sin6_scope_id field) + AC_TRY_COMPILE([#include <sys/types.h> +#include <netinet/in.h> +],[static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIN6_SCOPE_ID)], + AC_MSG_RESULT(no)) +fi + +dnl ---------------------------- +dnl check socklen_t exist or not +dnl ---------------------------- +AC_MSG_CHECKING(whther socklen_t is defined) +AC_TRY_COMPILE([#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +],[socklen_t ac_x;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKLEN_T)], + AC_MSG_RESULT(no)) + +dnl ------------------------ +dnl check struct sockaddr_dl +dnl ------------------------ +AC_MSG_CHECKING(whether struct sockaddr_dl exist) +AC_EGREP_HEADER(sockaddr_dl, +net/if_dl.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SOCKADDR_DL)], + AC_MSG_RESULT(no)) + +dnl -------------------------- +dnl check structure ifaliasreq +dnl -------------------------- +AC_MSG_CHECKING(whether struct ifaliasreq exist) +AC_EGREP_HEADER(ifaliasreq, +net/if.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IFALIASREQ)], + AC_MSG_RESULT(no)) + +dnl ---------------------------- +dnl check structure in6_aliasreq +dnl ---------------------------- +AC_MSG_CHECKING(whether struct if6_aliasreq exist) +AC_EGREP_HEADER(in6_aliasreq, +netinet6/in6_var.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IN6_ALIASREQ)], + AC_MSG_RESULT(no)) + +dnl --------------------------- +dnl check structure rt_addrinfo +dnl --------------------------- +AC_MSG_CHECKING(whether struct rt_addrinfo exist) +AC_EGREP_HEADER(rt_addrinfo, +net/route.h, +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RT_ADDRINFO)], + AC_MSG_RESULT(no)) + +dnl -------------------------- +dnl check structure in_pktinfo +dnl -------------------------- +AC_MSG_CHECKING(whether struct in_pktinfo exist) +AC_TRY_COMPILE([#include <netinet/in.h> +],[struct in_pktinfo ac_x;], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_INPKTINFO)], + AC_MSG_RESULT(no)) + +dnl -------------------------------------- +dnl checking for getrusage struct and call +dnl -------------------------------------- +AC_MSG_CHECKING(whether getrusage is available) +AC_TRY_COMPILE([#include <sys/resource.h> +],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RUSAGE)], + AC_MSG_RESULT(no)) + +dnl ------------- +dnl check version +dnl ------------- +file="${srcdir}/lib/version.h" +VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file` +AC_SUBST(VERSION) + +dnl ------------------------------ +dnl set paths for process id files +dnl ------------------------------ +AC_CACHE_CHECK(pid file directory,ac_piddir, +[for ZEBRA_PID_DIR in /var/run dnl + /var/adm dnl + /etc dnl + /dev/null; +do + test -d $ZEBRA_PID_DIR && break +done +ac_piddir=$ZEBRA_PID_DIR +if test $ZEBRA_PID_DIR = "/dev/null"; then + echo "PID DIRECTORY NOT FOUND!" +fi]) +AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$ac_piddir/zebra.pid") +AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$ac_piddir/ripd.pid") +AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$ac_piddir/ripngd.pid") +AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$ac_piddir/bgpd.pid") +AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$ac_piddir/ospfd.pid") +AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$ac_piddir/ospf6d.pid") +AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$ac_piddir/isisd.pid") + +dnl --------------------------- +dnl Check htonl works correctly +dnl --------------------------- +AC_MSG_CHECKING(for working htonl) +AC_CACHE_VAL(ac_cv_htonl_works, [ +AC_TRY_LINK([#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif], +[htonl (0);], +ac_cv_htonl_works=yes, +ac_cv_htonl_works=no)]) +AC_MSG_RESULT($ac_cv_htonl_works) + +AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile) + +echo " +zebra configuration +------------------- +zebra version : ${VERSION} +host operationg system : ${host_os} +source code location : ${srcdir} +compiler : ${CC} +compiler flags : ${CFLAGS} +directory for pid files : ${ac_piddir} +" diff --git a/isisd/modified/log.c b/isisd/modified/log.c new file mode 100644 index 00000000..385fb38f --- /dev/null +++ b/isisd/modified/log.c @@ -0,0 +1,484 @@ +/* Logging of zebra + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "log.h" +#include "memory.h" +#include "command.h" + +struct zlog *zlog_default = NULL; + +const char *zlog_proto_names[] = +{ + "NONE", + "DEFAULT", + "ZEBRA", + "RIP", + "BGP", + "OSPF", + "RIPNG", + "OSPF6", + "ISIS", + "MASC", + NULL, +}; + +const char *zlog_priority[] = +{ + "emergencies", + "alerts", + "critical", + "errors", + "warnings", + "notifications", + "informational", + "debugging", + NULL, +}; + + + +/* For time string format. */ +#define TIME_BUF 27 + +/* Utility routine for current time printing. */ +static void +time_print (FILE *fp) +{ + int ret; + char buf [TIME_BUF]; + time_t clock; + struct tm *tm; + + time (&clock); + tm = localtime (&clock); + + ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); + if (ret == 0) { + zlog_warn ("strftime error"); + } + + fprintf (fp, "%s ", buf); +} + +/* va_list version of zlog. */ +void +vzlog (struct zlog *zl, int priority, const char *format, va_list *args) +{ + /* If zlog is not specified, use default one. */ + if (zl == NULL) + zl = zlog_default; + + /* When zlog_default is also NULL, use stderr for logging. */ + if (zl == NULL) + { + time_print (stderr); + fprintf (stderr, "%s: ", "unknown"); + vfprintf (stderr, format, args[ZLOG_NOLOG_INDEX]); + fprintf (stderr, "\n"); + fflush (stderr); + + /* In this case we return at here. */ + return; + } + + /* only log this information if it has not been masked out */ + if ( priority > zl->maskpri ) + return ; + + /* Syslog output */ + if (zl->flags & ZLOG_SYSLOG) + vsyslog (priority, format, args[ZLOG_SYSLOG_INDEX]); + + /* File output. */ + if (zl->flags & ZLOG_FILE) + { + time_print (zl->fp); + if (zl->record_priority) fprintf (zl->fp, "%s: ", zlog_priority[priority]); + fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (zl->fp, format, args[ZLOG_FILE_INDEX]); + fprintf (zl->fp, "\n"); + fflush (zl->fp); + } + + /* stdout output. */ + if (zl->flags & ZLOG_STDOUT) + { + time_print (stdout); + if (zl->record_priority) fprintf (stdout, "%s: ", zlog_priority[priority]); + fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (stdout, format, args[ZLOG_STDOUT_INDEX]); + fprintf (stdout, "\n"); + fflush (stdout); + } + + /* stderr output. */ + if (zl->flags & ZLOG_STDERR) + { + time_print (stderr); + if (zl->record_priority) fprintf (stderr, "%s: ", zlog_priority[priority]); + fprintf (stderr, "%s: ", zlog_proto_names[zl->protocol]); + vfprintf (stderr, format, args[ZLOG_STDERR_INDEX]); + fprintf (stderr, "\n"); + fflush (stderr); + } + + /* Terminal monitor. */ + vty_log (zlog_proto_names[zl->protocol], format, args[ZLOG_NOLOG_INDEX]); +} + +void +zlog (struct zlog *zl, int priority, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, priority, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_err (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_ERR, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_warn (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_WARNING, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_info (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_INFO, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_notice (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_NOTICE, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +zlog_debug (const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (NULL, LOG_DEBUG, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_err (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_ERR, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_warn (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_WARNING, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_info (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_INFO, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_notice (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_NOTICE, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + +void +plog_debug (struct zlog *zl, const char *format, ...) +{ + va_list args[ZLOG_MAX_INDEX]; + int index; + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_start(args[index], format); + + vzlog (zl, LOG_DEBUG, format, args); + + for (index = 0; index < ZLOG_MAX_INDEX; index++) + va_end (args[index]); +} + + +/* Open log stream */ +struct zlog * +openzlog (const char *progname, int flags, zlog_proto_t protocol, + int syslog_flags, int syslog_facility) +{ + struct zlog *zl; + + zl = XMALLOC(MTYPE_ZLOG, sizeof (struct zlog)); + memset (zl, 0, sizeof (struct zlog)); + + zl->ident = progname; + zl->flags = flags; + zl->protocol = protocol; + zl->facility = syslog_facility; + zl->maskpri = LOG_DEBUG; + zl->record_priority = 0; + + openlog (progname, syslog_flags, zl->facility); + + return zl; +} + +void +closezlog (struct zlog *zl) +{ + closelog(); + fclose (zl->fp); + + XFREE (MTYPE_ZLOG, zl); +} + +/* Called from command.c. */ +void +zlog_set_flag (struct zlog *zl, int flags) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags |= flags; +} + +void +zlog_reset_flag (struct zlog *zl, int flags) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags &= ~flags; +} + +int +zlog_set_file (struct zlog *zl, int flags, char *filename) +{ + FILE *fp; + + /* There is opend file. */ + zlog_reset_file (zl); + + /* Set default zl. */ + if (zl == NULL) + zl = zlog_default; + + /* Open file. */ + fp = fopen (filename, "a"); + if (fp == NULL) + return 0; + + /* Set flags. */ + zl->filename = strdup (filename); + zl->flags |= ZLOG_FILE; + zl->fp = fp; + + return 1; +} + +/* Reset opend file. */ +int +zlog_reset_file (struct zlog *zl) +{ + if (zl == NULL) + zl = zlog_default; + + zl->flags &= ~ZLOG_FILE; + + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + + if (zl->filename) + free (zl->filename); + zl->filename = NULL; + + return 1; +} + +/* Reopen log file. */ +int +zlog_rotate (struct zlog *zl) +{ + FILE *fp; + + if (zl == NULL) + zl = zlog_default; + + if (zl->fp) + fclose (zl->fp); + zl->fp = NULL; + + if (zl->filename) + { + fp = fopen (zl->filename, "a"); + if (fp == NULL) + return -1; + zl->fp = fp; + } + + return 1; +} + +static char *zlog_cwd = NULL; + +void +zlog_save_cwd () +{ + char *cwd; + + cwd = getcwd (NULL, MAXPATHLEN); + + zlog_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1); + strcpy (zlog_cwd, cwd); +} + +char * +zlog_get_cwd () +{ + return zlog_cwd; +} + +void +zlog_free_cwd () +{ + if (zlog_cwd) + XFREE (MTYPE_TMP, zlog_cwd); +} + +/* Message lookup function. */ +char * +lookup (struct message *mes, int key) +{ + struct message *pnt; + + for (pnt = mes; pnt->key != 0; pnt++) + if (pnt->key == key) + return pnt->str; + + return ""; +} + +/* Very old hacky version of message lookup function. Still partly + used in bgpd and ospfd. */ +char * +mes_lookup (struct message *meslist, int max, int index) +{ + if (index < 0 || index >= max) + { + zlog_err ("message index out of bound: %d", max); + return NULL; + } + return meslist[index].str; +} diff --git a/isisd/modified/log.h b/isisd/modified/log.h new file mode 100644 index 00000000..8948ea00 --- /dev/null +++ b/isisd/modified/log.h @@ -0,0 +1,129 @@ +/* Zebra logging funcions. + * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_LOG_H +#define _ZEBRA_LOG_H + +#include <syslog.h> + +#define ZLOG_NOLOG 0x00 +#define ZLOG_FILE 0x01 +#define ZLOG_SYSLOG 0x02 +#define ZLOG_STDOUT 0x04 +#define ZLOG_STDERR 0x08 + +#define ZLOG_NOLOG_INDEX 0 +#define ZLOG_FILE_INDEX 1 +#define ZLOG_SYSLOG_INDEX 2 +#define ZLOG_STDOUT_INDEX 3 +#define ZLOG_STDERR_INDEX 4 +#define ZLOG_MAX_INDEX 5 + +typedef enum +{ + ZLOG_NONE, + ZLOG_DEFAULT, + ZLOG_ZEBRA, + ZLOG_RIP, + ZLOG_BGP, + ZLOG_OSPF, + ZLOG_RIPNG, + ZLOG_OSPF6, + ZLOG_ISIS, + ZLOG_MASC +} zlog_proto_t; + +struct zlog +{ + const char *ident; + zlog_proto_t protocol; + int flags; + FILE *fp; + char *filename; + int syslog; + int stat; + int connected; + int maskpri; /* as per syslog setlogmask */ + int priority; /* as per syslog priority */ + int facility; /* as per syslog facility */ + int record_priority; +}; + +/* Message structure. */ +struct message +{ + int key; + char *str; +}; + +/* Default logging strucutre. */ +extern struct zlog *zlog_default; + +/* Open zlog function */ +struct zlog *openzlog (const char *, int, zlog_proto_t, int, int); + +/* Close zlog function. */ +void closezlog (struct zlog *zl); + +/* GCC have printf type attribute check. */ +#ifdef __GNUC__ +#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#else +#define PRINTF_ATTRIBUTE(a,b) +#endif /* __GNUC__ */ + +/* Generic function for zlog. */ +void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4); + +/* Handy zlog functions. */ +void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); + +/* For bgpd's peer oriented log. */ +void plog_err (struct zlog *, const char *format, ...); +void plog_warn (struct zlog *, const char *format, ...); +void plog_info (struct zlog *, const char *format, ...); +void plog_notice (struct zlog *, const char *format, ...); +void plog_debug (struct zlog *, const char *format, ...); + +/* Set zlog flags. */ +void zlog_set_flag (struct zlog *zl, int flags); +void zlog_reset_flag (struct zlog *zl, int flags); + +/* Set zlog filename. */ +int zlog_set_file (struct zlog *zl, int flags, char *filename); +int zlog_reset_file (struct zlog *zl); + +/* Rotate log. */ +int zlog_rotate (); + +/* For hackey massage lookup and check */ +#define LOOKUP(x, y) mes_lookup(x, x ## _max, y) + +char *lookup (struct message *, int); +char *mes_lookup (struct message *meslist, int max, int index); + +extern const char *zlog_priority[]; + +#endif /* _ZEBRA_LOG_H */ diff --git a/isisd/modified/memory.c b/isisd/modified/memory.c new file mode 100644 index 00000000..49ff3213 --- /dev/null +++ b/isisd/modified/memory.c @@ -0,0 +1,527 @@ +/* + * 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 <zebra.h> + +#include "log.h" +#include "memory.h" + +void alloc_inc (int); +void alloc_dec (int); + +struct message mstr [] = +{ + { MTYPE_THREAD, "thread" }, + { MTYPE_THREAD_MASTER, "thread_master" }, + { MTYPE_VECTOR, "vector" }, + { MTYPE_VECTOR_INDEX, "vector_index" }, + { MTYPE_IF, "interface" }, + { 0, NULL }, +}; + +/* Fatal memory allocation error occured. */ +static void +zerror (const char *fname, int type, size_t size) +{ + fprintf (stderr, "%s : can't allocate memory for `%s' size %d\n", + fname, lookup (mstr, type), (int) size); + exit (1); +} + +/* Memory allocation. */ +void * +zmalloc (int type, size_t size) +{ + void *memory; + + memory = malloc (size); + + if (memory == NULL) + zerror ("malloc", type, size); + + alloc_inc (type); + + return memory; +} + +/* Memory allocation with num * size with cleared. */ +void * +zcalloc (int type, size_t size) +{ + void *memory; + + memory = calloc (1, size); + + if (memory == NULL) + zerror ("calloc", type, size); + + alloc_inc (type); + + return memory; +} + +/* Memory reallocation. */ +void * +zrealloc (int type, void *ptr, size_t size) +{ + void *memory; + + memory = realloc (ptr, size); + if (memory == NULL) + zerror ("realloc", type, size); + return memory; +} + +/* Memory free. */ +void +zfree (int type, void *ptr) +{ + alloc_dec (type); + free (ptr); +} + +/* String duplication. */ +char * +zstrdup (int type, char *str) +{ + void *dup; + + dup = strdup (str); + if (dup == NULL) + zerror ("strdup", type, strlen (str)); + alloc_inc (type); + return dup; +} + +#ifdef MEMORY_LOG +struct +{ + char *name; + unsigned long alloc; + unsigned long t_malloc; + unsigned long c_malloc; + unsigned long t_calloc; + unsigned long c_calloc; + unsigned long t_realloc; + unsigned long t_free; + unsigned long c_strdup; +} mstat [MTYPE_MAX]; + +void +mtype_log (char *func, void *memory, const char *file, int line, int type) +{ + zlog_info ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line); +} + +void * +mtype_zmalloc (const char *file, int line, int type, size_t size) +{ + void *memory; + + mstat[type].c_malloc++; + mstat[type].t_malloc++; + + memory = zmalloc (type, size); + mtype_log ("zmalloc", memory, file, line, type); + + return memory; +} + +void * +mtype_zcalloc (const char *file, int line, int type, size_t size) +{ + void *memory; + + mstat[type].c_calloc++; + mstat[type].t_calloc++; + + memory = zcalloc (type, size); + mtype_log ("xcalloc", memory, file, line, type); + + return memory; +} + +void * +mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size) +{ + void *memory; + + /* Realloc need before allocated pointer. */ + mstat[type].t_realloc++; + + memory = zrealloc (type, ptr, size); + + mtype_log ("xrealloc", memory, file, line, type); + + return memory; +} + +/* Important function. */ +void +mtype_zfree (const char *file, int line, int type, void *ptr) +{ + mstat[type].t_free++; + + mtype_log ("xfree", ptr, file, line, type); + + zfree (type, ptr); +} + +char * +mtype_zstrdup (const char *file, int line, int type, char *str) +{ + char *memory; + + mstat[type].c_strdup++; + + memory = zstrdup (type, str); + + mtype_log ("xstrdup", memory, file, line, type); + + return memory; +} +#else +struct +{ + char *name; + unsigned long alloc; +} mstat [MTYPE_MAX]; +#endif /* MTPYE_LOG */ + +/* Increment allocation counter. */ +void +alloc_inc (int type) +{ + mstat[type].alloc++; +} + +/* Decrement allocation counter. */ +void +alloc_dec (int type) +{ + mstat[type].alloc--; +} + +/* Looking up memory status from vty interface. */ +#include "vector.h" +#include "vty.h" +#include "command.h" + +/* For pretty printng of memory allocate information. */ +struct memory_list +{ + int index; + char *format; +}; + +struct memory_list memory_list_lib[] = +{ + { MTYPE_TMP, "Temporary memory" }, + { MTYPE_ROUTE_TABLE, "Route table " }, + { MTYPE_ROUTE_NODE, "Route node " }, + { MTYPE_RIB, "RIB " }, + { MTYPE_NEXTHOP, "Nexthop " }, + { MTYPE_LINK_LIST, "Link List " }, + { MTYPE_LINK_NODE, "Link Node " }, + { MTYPE_HASH, "Hash " }, + { MTYPE_HASH_BACKET, "Hash Bucket " }, + { MTYPE_ACCESS_LIST, "Access List " }, + { MTYPE_ACCESS_LIST_STR, "Access List Str " }, + { MTYPE_ACCESS_FILTER, "Access Filter " }, + { MTYPE_PREFIX_LIST, "Prefix List " }, + { MTYPE_PREFIX_LIST_STR, "Prefix List Str " }, + { MTYPE_PREFIX_LIST_ENTRY, "Prefix List Entry "}, + { MTYPE_ROUTE_MAP, "Route map " }, + { MTYPE_ROUTE_MAP_NAME, "Route map name " }, + { MTYPE_ROUTE_MAP_INDEX, "Route map index " }, + { MTYPE_ROUTE_MAP_RULE, "Route map rule " }, + { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" }, + { MTYPE_DESC, "Command desc " }, + { MTYPE_BUFFER, "Buffer " }, + { MTYPE_BUFFER_DATA, "Buffer data " }, + { MTYPE_STREAM, "Stream " }, + { MTYPE_KEYCHAIN, "Key chain " }, + { MTYPE_KEY, "Key " }, + { MTYPE_VTY, "VTY " }, + { -1, NULL } +}; + +struct memory_list memory_list_bgp[] = +{ + { MTYPE_BGP_PEER, "BGP peer" }, + { MTYPE_ATTR, "BGP attribute" }, + { MTYPE_AS_PATH, "BGP aspath" }, + { MTYPE_AS_SEG, "BGP aspath seg" }, + { MTYPE_AS_STR, "BGP aspath str" }, + { 0, NULL }, + { MTYPE_BGP_TABLE, "BGP table" }, + { MTYPE_BGP_NODE, "BGP node" }, + { MTYPE_BGP_ADVERTISE_ATTR, "BGP adv attr" }, + { MTYPE_BGP_ADVERTISE, "BGP adv" }, + { MTYPE_BGP_ADJ_IN, "BGP adj in" }, + { MTYPE_BGP_ADJ_OUT, "BGP adj out" }, + { 0, NULL }, + { MTYPE_AS_LIST, "BGP AS list" }, + { MTYPE_AS_FILTER, "BGP AS filter" }, + { MTYPE_AS_FILTER_STR, "BGP AS filter str" }, + { 0, NULL }, + { MTYPE_COMMUNITY, "community" }, + { MTYPE_COMMUNITY_VAL, "community val" }, + { MTYPE_COMMUNITY_STR, "community str" }, + { 0, NULL }, + { MTYPE_ECOMMUNITY, "extcommunity" }, + { MTYPE_ECOMMUNITY_VAL, "extcommunity val" }, + { MTYPE_ECOMMUNITY_STR, "extcommunity str" }, + { 0, NULL }, + { MTYPE_COMMUNITY_LIST, "community-list" }, + { MTYPE_COMMUNITY_LIST_NAME, "community-list name" }, + { MTYPE_COMMUNITY_LIST_ENTRY, "community-list entry" }, + { MTYPE_COMMUNITY_LIST_CONFIG, "community-list config" }, + { 0, NULL }, + { MTYPE_CLUSTER, "Cluster list" }, + { MTYPE_CLUSTER_VAL, "Cluster list val" }, + { 0, NULL }, + { MTYPE_TRANSIT, "BGP transit attr" }, + { MTYPE_TRANSIT_VAL, "BGP transit val" }, + { 0, NULL }, + { MTYPE_BGP_DISTANCE, "BGP distance" }, + { MTYPE_BGP_NEXTHOP_CACHE, "BGP nexthop" }, + { MTYPE_BGP_CONFED_LIST, "BGP confed list" }, + { MTYPE_PEER_UPDATE_SOURCE, "peer update if" }, + { MTYPE_BGP_DAMP_INFO, "Dampening info" }, + { MTYPE_BGP_REGEXP, "BGP regexp" }, + { -1, NULL } +}; + +struct memory_list memory_list_rip[] = +{ + { MTYPE_RIP, "RIP structure " }, + { MTYPE_RIP_INFO, "RIP route info " }, + { MTYPE_RIP_INTERFACE, "RIP interface " }, + { MTYPE_RIP_PEER, "RIP peer " }, + { MTYPE_RIP_OFFSET_LIST, "RIP offset list " }, + { MTYPE_RIP_DISTANCE, "RIP distance " }, + { -1, NULL } +}; + +struct memory_list memory_list_ospf[] = +{ + { MTYPE_OSPF_TOP, "OSPF top " }, + { MTYPE_OSPF_AREA, "OSPF area " }, + { MTYPE_OSPF_AREA_RANGE, "OSPF area range " }, + { MTYPE_OSPF_NETWORK, "OSPF network " }, +#ifdef NBMA_ENABLE + { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " }, +#endif /* NBMA_ENABLE */ + { MTYPE_OSPF_IF, "OSPF interface " }, + { MTYPE_OSPF_NEIGHBOR, "OSPF neighbor " }, + { MTYPE_OSPF_ROUTE, "OSPF route " }, + { MTYPE_OSPF_TMP, "OSPF tmp mem " }, + { MTYPE_OSPF_LSA, "OSPF LSA " }, + { MTYPE_OSPF_LSA_DATA, "OSPF LSA data " }, + { MTYPE_OSPF_LSDB, "OSPF LSDB " }, + { MTYPE_OSPF_PACKET, "OSPF packet " }, + { MTYPE_OSPF_FIFO, "OSPF FIFO queue " }, + { MTYPE_OSPF_VERTEX, "OSPF vertex " }, + { MTYPE_OSPF_NEXTHOP, "OSPF nexthop " }, + { MTYPE_OSPF_PATH, "OSPF path " }, + { MTYPE_OSPF_VL_DATA, "OSPF VL data " }, + { MTYPE_OSPF_CRYPT_KEY, "OSPF crypt key " }, + { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info " }, + { MTYPE_OSPF_DISTANCE, "OSPF distance " }, + { MTYPE_OSPF_IF_INFO, "OSPF if info " }, + { MTYPE_OSPF_IF_PARAMS, "OSPF if params " }, + { -1, NULL }, +}; + +struct memory_list memory_list_ospf6[] = +{ + { MTYPE_OSPF6_TOP, "OSPF6 top " }, + { MTYPE_OSPF6_AREA, "OSPF6 area " }, + { MTYPE_OSPF6_IF, "OSPF6 interface " }, + { MTYPE_OSPF6_NEIGHBOR, "OSPF6 neighbor " }, + { MTYPE_OSPF6_ROUTE, "OSPF6 route " }, + { MTYPE_OSPF6_PREFIX, "OSPF6 prefix " }, + { MTYPE_OSPF6_MESSAGE, "OSPF6 message " }, + { MTYPE_OSPF6_LSA, "OSPF6 LSA " }, + { MTYPE_OSPF6_LSA_SUMMARY, "OSPF6 LSA summary " }, + { MTYPE_OSPF6_LSDB, "OSPF6 LSA database" }, + { MTYPE_OSPF6_VERTEX, "OSPF6 vertex " }, + { MTYPE_OSPF6_SPFTREE, "OSPF6 SPF tree " }, + { MTYPE_OSPF6_NEXTHOP, "OSPF6 nexthop " }, + { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info " }, + { MTYPE_OSPF6_OTHER, "OSPF6 other " }, + { -1, NULL }, +}; + + +struct memory_list memory_list_isis[] = +{ + { MTYPE_ISIS, "ISIS : %ld\r\n" }, + { MTYPE_ISIS_TMP, "ISIS TMP : %ld\r\n" }, + { MTYPE_ISIS_CIRCUIT, "ISIS circuit : %ld\r\n" }, + { MTYPE_ISIS_LSP, "ISIS LSP : %ld\r\n" }, + { MTYPE_ISIS_ADJACENCY, "ISIS adjacency : %ld\r\n" }, + { MTYPE_ISIS_AREA, "ISIS area : %ld\r\n" }, + { MTYPE_ISIS_AREA_ADDR, "ISIS area address: %ld\r\n" }, + { MTYPE_ISIS_TLV, "ISIS TLV : %ld\r\n" }, + { MTYPE_ISIS_DYNHN, "ISIS dyn hostname: %ld\r\n" }, + { MTYPE_ISIS_SPFTREE, "ISIS SPFtree : %ld\r\n" }, + { MTYPE_ISIS_VERTEX, "ISIS vertex : %ld\r\n" }, + { MTYPE_ISIS_ROUTE_INFO, "ISIS route info : %ld\r\n" }, + { MTYPE_ISIS_NEXTHOP, "ISIS nexthop : %ld\r\n" }, + { MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6 : %ld\r\n" }, + { -1, NULL }, +}; + +struct memory_list memory_list_separator[] = +{ + { 0, NULL}, + {-1, NULL} +}; + +void +show_memory_vty (struct vty *vty, struct memory_list *list) +{ + struct memory_list *m; + + for (m = list; m->index >= 0; m++) + if (m->index == 0) + vty_out (vty, "-----------------------------\r\n"); + else + vty_out (vty, "%-22s: %5ld\r\n", m->format, mstat[m->index].alloc); +} + +DEFUN (show_memory_all, + show_memory_all_cmd, + "show memory all", + "Show running system information\n" + "Memory statistics\n" + "All memory statistics\n") +{ + show_memory_vty (vty, memory_list_lib); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_rip); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_ospf); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_ospf6); + show_memory_vty (vty, memory_list_separator); + show_memory_vty (vty, memory_list_bgp); + + return CMD_SUCCESS; +} + +ALIAS (show_memory_all, + show_memory_cmd, + "show memory", + "Show running system information\n" + "Memory statistics\n") + +DEFUN (show_memory_lib, + show_memory_lib_cmd, + "show memory lib", + SHOW_STR + "Memory statistics\n" + "Library memory\n") +{ + show_memory_vty (vty, memory_list_lib); + return CMD_SUCCESS; +} + +DEFUN (show_memory_rip, + show_memory_rip_cmd, + "show memory rip", + SHOW_STR + "Memory statistics\n" + "RIP memory\n") +{ + show_memory_vty (vty, memory_list_rip); + return CMD_SUCCESS; +} + +DEFUN (show_memory_bgp, + show_memory_bgp_cmd, + "show memory bgp", + SHOW_STR + "Memory statistics\n" + "BGP memory\n") +{ + show_memory_vty (vty, memory_list_bgp); + return CMD_SUCCESS; +} + +DEFUN (show_memory_ospf, + show_memory_ospf_cmd, + "show memory ospf", + SHOW_STR + "Memory statistics\n" + "OSPF memory\n") +{ + show_memory_vty (vty, memory_list_ospf); + return CMD_SUCCESS; +} + +DEFUN (show_memory_ospf6, + show_memory_ospf6_cmd, + "show memory ospf6", + SHOW_STR + "Memory statistics\n" + "OSPF6 memory\n") +{ + show_memory_vty (vty, memory_list_ospf6); + return CMD_SUCCESS; +} + + +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 () +{ + install_element (VIEW_NODE, &show_memory_cmd); + install_element (VIEW_NODE, &show_memory_all_cmd); + install_element (VIEW_NODE, &show_memory_lib_cmd); + install_element (VIEW_NODE, &show_memory_rip_cmd); + install_element (VIEW_NODE, &show_memory_bgp_cmd); + install_element (VIEW_NODE, &show_memory_ospf_cmd); + install_element (VIEW_NODE, &show_memory_ospf6_cmd); + install_element (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_rip_cmd); + install_element (ENABLE_NODE, &show_memory_bgp_cmd); + install_element (ENABLE_NODE, &show_memory_ospf_cmd); + install_element (ENABLE_NODE, &show_memory_ospf6_cmd); + install_element (ENABLE_NODE, &show_memory_isis_cmd); +} diff --git a/isisd/modified/memory.h b/isisd/modified/memory.h new file mode 100644 index 00000000..d80cdf5f --- /dev/null +++ b/isisd/modified/memory.h @@ -0,0 +1,257 @@ +/* Memory management routine + Copyright (C) 1998 Kunihiro Ishiguro + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _ZEBRA_MEMORY_H +#define _ZEBRA_MEMORY_H + +/* #define MEMORY_LOG */ + +/* For tagging memory, below is the type of the memory. */ +enum +{ + MTYPE_TMP = 1, + MTYPE_STRVEC, + MTYPE_VECTOR, + MTYPE_VECTOR_INDEX, + MTYPE_LINK_LIST, + MTYPE_LINK_NODE, + MTYPE_THREAD, + MTYPE_THREAD_MASTER, + MTYPE_VTY, + MTYPE_VTY_HIST, + MTYPE_VTY_OUT_BUF, + MTYPE_IF, + MTYPE_CONNECTED, + MTYPE_AS_SEG, + MTYPE_AS_STR, + MTYPE_AS_PATH, + MTYPE_CLUSTER, + MTYPE_CLUSTER_VAL, + MTYPE_ATTR, + MTYPE_TRANSIT, + MTYPE_TRANSIT_VAL, + MTYPE_BUFFER, + MTYPE_BUFFER_DATA, + MTYPE_STREAM, + MTYPE_STREAM_DATA, + MTYPE_STREAM_FIFO, + MTYPE_PREFIX, + MTYPE_PREFIX_IPV4, + MTYPE_PREFIX_IPV6, + MTYPE_HASH, + MTYPE_HASH_INDEX, + MTYPE_HASH_BACKET, + MTYPE_RIPNG_ROUTE, + MTYPE_RIPNG_AGGREGATE, + MTYPE_ROUTE_TABLE, + MTYPE_ROUTE_NODE, + MTYPE_ACCESS_LIST, + MTYPE_ACCESS_LIST_STR, + MTYPE_ACCESS_FILTER, + MTYPE_PREFIX_LIST, + MTYPE_PREFIX_LIST_STR, + MTYPE_PREFIX_LIST_ENTRY, + MTYPE_ROUTE_MAP, + MTYPE_ROUTE_MAP_NAME, + MTYPE_ROUTE_MAP_INDEX, + MTYPE_ROUTE_MAP_RULE, + MTYPE_ROUTE_MAP_RULE_STR, + MTYPE_ROUTE_MAP_COMPILED, + + MTYPE_RIB, + MTYPE_DISTRIBUTE, + MTYPE_ZLOG, + MTYPE_ZCLIENT, + MTYPE_NEXTHOP, + MTYPE_RTADV_PREFIX, + MTYPE_IF_RMAP, + MTYPE_SOCKUNION, + MTYPE_STATIC_IPV4, + MTYPE_STATIC_IPV6, + + MTYPE_DESC, + MTYPE_OSPF_TOP, + MTYPE_OSPF_AREA, + MTYPE_OSPF_AREA_RANGE, + MTYPE_OSPF_NETWORK, + MTYPE_OSPF_NEIGHBOR_STATIC, + MTYPE_OSPF_IF, + MTYPE_OSPF_NEIGHBOR, + MTYPE_OSPF_ROUTE, + MTYPE_OSPF_TMP, + MTYPE_OSPF_LSA, + MTYPE_OSPF_LSA_DATA, + MTYPE_OSPF_LSDB, + MTYPE_OSPF_PACKET, + MTYPE_OSPF_FIFO, + MTYPE_OSPF_VERTEX, + MTYPE_OSPF_NEXTHOP, + MTYPE_OSPF_PATH, + MTYPE_OSPF_VL_DATA, + MTYPE_OSPF_CRYPT_KEY, + MTYPE_OSPF_EXTERNAL_INFO, + MTYPE_OSPF_MESSAGE, + MTYPE_OSPF_DISTANCE, + MTYPE_OSPF_IF_INFO, + MTYPE_OSPF_IF_PARAMS, + + MTYPE_OSPF6_TOP, + MTYPE_OSPF6_AREA, + MTYPE_OSPF6_IF, + MTYPE_OSPF6_NEIGHBOR, + MTYPE_OSPF6_ROUTE, + MTYPE_OSPF6_PREFIX, + MTYPE_OSPF6_MESSAGE, + MTYPE_OSPF6_LSA, + MTYPE_OSPF6_LSA_SUMMARY, + MTYPE_OSPF6_LSDB, + MTYPE_OSPF6_VERTEX, + MTYPE_OSPF6_SPFTREE, + MTYPE_OSPF6_NEXTHOP, + MTYPE_OSPF6_EXTERNAL_INFO, + MTYPE_OSPF6_OTHER, + + MTYPE_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_BGP, + MTYPE_BGP_PEER, + MTYPE_PEER_GROUP, + MTYPE_PEER_DESC, + MTYPE_PEER_UPDATE_SOURCE, + MTYPE_BGP_STATIC, + MTYPE_BGP_AGGREGATE, + MTYPE_BGP_CONFED_LIST, + MTYPE_BGP_NEXTHOP_CACHE, + MTYPE_BGP_DAMP_INFO, + MTYPE_BGP_DAMP_ARRAY, + MTYPE_BGP_ANNOUNCE, + MTYPE_BGP_ATTR_QUEUE, + MTYPE_BGP_ROUTE_QUEUE, + MTYPE_BGP_DISTANCE, + MTYPE_BGP_ROUTE, + MTYPE_BGP_TABLE, + MTYPE_BGP_NODE, + MTYPE_BGP_ADVERTISE_ATTR, + MTYPE_BGP_ADVERTISE, + MTYPE_BGP_ADJ_IN, + MTYPE_BGP_ADJ_OUT, + MTYPE_BGP_REGEXP, + MTYPE_AS_FILTER, + MTYPE_AS_FILTER_STR, + MTYPE_AS_LIST, + + MTYPE_COMMUNITY, + MTYPE_COMMUNITY_VAL, + MTYPE_COMMUNITY_STR, + + MTYPE_ECOMMUNITY, + MTYPE_ECOMMUNITY_VAL, + MTYPE_ECOMMUNITY_STR, + + /* community-list and extcommunity-list. */ + MTYPE_COMMUNITY_LIST_HANDLER, + MTYPE_COMMUNITY_LIST, + MTYPE_COMMUNITY_LIST_NAME, + MTYPE_COMMUNITY_LIST_ENTRY, + MTYPE_COMMUNITY_LIST_CONFIG, + + MTYPE_RIP, + MTYPE_RIP_INTERFACE, + MTYPE_RIP_DISTANCE, + MTYPE_RIP_OFFSET_LIST, + MTYPE_RIP_INFO, + MTYPE_RIP_PEER, + MTYPE_KEYCHAIN, + MTYPE_KEY, + + MTYPE_VTYSH_CONFIG, + MTYPE_VTYSH_CONFIG_LINE, + + MTYPE_MAX +}; + +#ifdef MEMORY_LOG +#define XMALLOC(mtype, size) \ + mtype_zmalloc (__FILE__, __LINE__, (mtype), (size)) +#define XCALLOC(mtype, size) \ + mtype_zcalloc (__FILE__, __LINE__, (mtype), (size)) +#define XREALLOC(mtype, ptr, size) \ + mtype_zrealloc (__FILE__, __LINE__, (mtype), (ptr), (size)) +#define XFREE(mtype, ptr) \ + mtype_zfree (__FILE__, __LINE__, (mtype), (ptr)) +#define XSTRDUP(mtype, str) \ + mtype_zstrdup (__FILE__, __LINE__, (mtype), (str)) +#else +#define XMALLOC(mtype, size) zmalloc ((mtype), (size)) +#define XCALLOC(mtype, size) zcalloc ((mtype), (size)) +#define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size)) +#define XFREE(mtype, ptr) zfree ((mtype), (ptr)) +#define XSTRDUP(mtype, str) zstrdup ((mtype), (str)) +#endif /* MEMORY_LOG */ + +/* Prototypes of memory function. */ +void *zmalloc (int type, size_t size); +void *zcalloc (int type, size_t size); +void *zrealloc (int type, void *ptr, size_t size); +void zfree (int type, void *ptr); +char *zstrdup (int type, char *str); + +void *mtype_zmalloc (const char *file, + int line, + int type, + size_t size); + +void *mtype_zcalloc (const char *file, + int line, + int type, + size_t num, + size_t size); + +void *mtype_zrealloc (const char *file, + int line, + int type, + void *ptr, + size_t size); + +void mtype_zfree (const char *file, + int line, + int type, + void *ptr); + +char *mtype_zstrdup (const char *file, + int line, + int type, + char *str); +void memory_init (); + +#endif /* _ZEBRA_MEMORY_H */ diff --git a/isisd/modified/rib.c b/isisd/modified/rib.c new file mode 100644 index 00000000..39a7690b --- /dev/null +++ b/isisd/modified/rib.c @@ -0,0 +1,3321 @@ +/* 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 <zebra.h> + +#include "prefix.h" +#include "table.h" +#include "memory.h" +#include "vty.h" +#include "str.h" +#include "command.h" +#include "linklist.h" +#include "if.h" +#include "log.h" +#include "sockunion.h" + +#include "zebra/rib.h" +#include "zebra/rt.h" +#include "zebra/zserv.h" +#include "zebra/redistribute.h" +#include "zebra/debug.h" + +/* Routing information base and static table for IPv4. */ +struct route_table *rib_table_ipv4; +struct route_table *static_table_ipv4; + +/* Routing information base and static table for IPv6. */ +#ifdef HAVE_IPV6 +struct route_table *rib_table_ipv6; +struct route_table *static_table_ipv6; +#endif /* HAVE_IPV6 */ + +/* Default rtm_table for all clients */ +extern int rtm_table_default; + +/* Each route type's string and default distance value. */ +struct +{ + int key; + char c; + char *str; + int distance; +} route_info[] = +{ + {ZEBRA_ROUTE_SYSTEM, 'X', "system", 0}, + {ZEBRA_ROUTE_KERNEL, 'K', "kernel", 0}, + {ZEBRA_ROUTE_CONNECT, 'C', "connected", 0}, + {ZEBRA_ROUTE_STATIC, 'S', "static", 1}, + {ZEBRA_ROUTE_RIP, 'R', "rip", 120}, + {ZEBRA_ROUTE_RIPNG, 'R', "ripng", 120}, + {ZEBRA_ROUTE_OSPF, 'O', "ospf", 110}, + {ZEBRA_ROUTE_OSPF6, 'O', "ospf6", 110}, + {ZEBRA_ROUTE_ISIS, 'I', "isis", 115}, + {ZEBRA_ROUTE_BGP, 'B', "bgp", 20 /* IBGP is 200. */} +}; + +/* Add nexthop to the end of the list. */ +void +nexthop_add (struct rib *rib, struct nexthop *nexthop) +{ + struct nexthop *last; + + for (last = rib->nexthop; last && last->next; last = last->next) + ; + if (last) + last->next = nexthop; + else + rib->nexthop = nexthop; + nexthop->prev = last; + + rib->nexthop_num++; +} + +/* Delete specified nexthop from the list. */ +void +nexthop_delete (struct rib *rib, struct nexthop *nexthop) +{ + if (nexthop->next) + nexthop->next->prev = nexthop->prev; + if (nexthop->prev) + nexthop->prev->next = nexthop->next; + else + rib->nexthop = nexthop->next; + rib->nexthop_num--; +} + +/* Free nexthop. */ +void +nexthop_free (struct nexthop *nexthop) +{ + if (nexthop->type == NEXTHOP_TYPE_IFNAME && nexthop->ifname) + free (nexthop->ifname); + XFREE (MTYPE_NEXTHOP, nexthop); +} + +struct nexthop * +nexthop_ifindex_add (struct rib *rib, unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IFINDEX; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ifname_add (struct rib *rib, char *ifname) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IFNAME; + nexthop->ifname = strdup (ifname); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV4; + nexthop->gate.ipv4 = *ipv4; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, + unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + nexthop->gate.ipv4 = *ipv4; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +#ifdef HAVE_IPV6 +struct nexthop * +nexthop_ipv6_add (struct rib *rib, struct in6_addr *ipv6) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6; + nexthop->gate.ipv6 = *ipv6; + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv6_ifname_add (struct rib *rib, struct in6_addr *ipv6, + char *ifname) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6_IFNAME; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifname = XSTRDUP (0, ifname); + + nexthop_add (rib, nexthop); + + return nexthop; +} + +struct nexthop * +nexthop_ipv6_ifindex_add (struct rib *rib, struct in6_addr *ipv6, + unsigned int ifindex) +{ + struct nexthop *nexthop; + + nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); + memset (nexthop, 0, sizeof (struct nexthop)); + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->gate.ipv6 = *ipv6; + nexthop->ifindex = ifindex; + + nexthop_add (rib, nexthop); + + return nexthop; +} +#endif /* HAVE_IPV6 */ + +/* If force flag is not set, do not modify falgs at all for uninstall + the route from FIB. */ +int +nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, + struct route_node *top) +{ + struct prefix_ipv4 p; + struct route_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; + + rn = route_node_match (rib_table_ipv4, (struct prefix *) &p); + while (rn) + { + route_unlock_node (rn); + + /* If lookup self prefix return immidiately. */ + if (rn == top) + return 0; + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + { + /* Directly point connected route. */ + newhop = match->nexthop; + if (newhop && nexthop->type == NEXTHOP_TYPE_IPV4) + nexthop->ifindex = newhop->ifindex; + + return 1; + } + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + nexthop->rtype = newhop->type; + if (newhop->type == NEXTHOP_TYPE_IPV4 || + newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + nexthop->rgate.ipv4 = newhop->gate.ipv4; + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX) + nexthop->rifindex = newhop->ifindex; + } + return 1; + } + return 0; + } + else + { + return 0; + } + } + } + return 0; +} + +#ifdef HAVE_IPV6 +/* If force flag is not set, do not modify falgs at all for uninstall + the route from FIB. */ +int +nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, + struct route_node *top) +{ + struct prefix_ipv6 p; + struct route_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; + + rn = route_node_match (rib_table_ipv6, (struct prefix *) &p); + while (rn) + { + route_unlock_node (rn); + + /* If lookup self prefix return immidiately. */ + if (rn == top) + return 0; + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + { + /* Directly point connected route. */ + newhop = match->nexthop; + + if (newhop && nexthop->type == NEXTHOP_TYPE_IPV6) + nexthop->ifindex = newhop->ifindex; + + return 1; + } + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) + && ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + if (set) + { + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE); + nexthop->rtype = newhop->type; + if (newhop->type == NEXTHOP_TYPE_IPV6 + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + nexthop->rgate.ipv6 = newhop->gate.ipv6; + if (newhop->type == NEXTHOP_TYPE_IFINDEX + || newhop->type == NEXTHOP_TYPE_IFNAME + || newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX + || newhop->type == NEXTHOP_TYPE_IPV6_IFNAME) + nexthop->rifindex = newhop->ifindex; + } + return 1; + } + return 0; + } + else + { + return 0; + } + } + } + return 0; +} +#endif /* HAVE_IPV6 */ + +struct rib * +rib_match_ipv4 (struct in_addr addr) +{ + struct prefix_ipv4 p; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + memset (&p, 0, sizeof (struct prefix_ipv4)); + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.prefix = addr; + + rn = route_node_match (rib_table_ipv4, (struct prefix *) &p); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} + +struct rib * +rib_lookup_ipv4 (struct prefix_ipv4 *p) +{ + struct route_node *rn; + struct rib *match; + struct nexthop *nexthop; + + rn = route_node_lookup (rib_table_ipv4, (struct prefix *) p); + + /* No route for this prefix. */ + if (! rn) + return NULL; + + /* Unlock node. */ + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + if (! match || match->type == ZEBRA_ROUTE_BGP) + return NULL; + + if (match->type == ZEBRA_ROUTE_CONNECT) + return match; + + for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + return match; + + return NULL; +} + +#ifdef HAVE_IPV6 +struct rib * +rib_match_ipv6 (struct in6_addr *addr) +{ + struct prefix_ipv6 p; + struct route_node *rn; + struct rib *match; + struct nexthop *newhop; + + 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 (rib_table_ipv6, (struct prefix *) &p); + + while (rn) + { + route_unlock_node (rn); + + /* Pick up selected route. */ + for (match = rn->info; match; match = match->next) + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + + /* If there is no selected route or matched route is EGP, go up + tree. */ + if (! match + || match->type == ZEBRA_ROUTE_BGP) + { + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node (rn); + } + else + { + if (match->type == ZEBRA_ROUTE_CONNECT) + /* Directly point connected route. */ + return match; + else + { + for (newhop = match->nexthop; newhop; newhop = newhop->next) + if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)) + return match; + return NULL; + } + } + } + return NULL; +} +#endif /* HAVE_IPV6 */ + +int +nexthop_active_check (struct route_node *rn, struct rib *rib, + struct nexthop *nexthop, int set) +{ + struct interface *ifp; + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IFINDEX: + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && if_is_up (ifp)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + case NEXTHOP_TYPE_IFNAME: + case NEXTHOP_TYPE_IPV6_IFNAME: + ifp = if_lookup_by_name (nexthop->ifname); + if (ifp && if_is_up (ifp)) + { + if (set) + nexthop->ifindex = ifp->ifindex; + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + if (set) + nexthop->ifindex = 0; + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop_active_ipv4 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; +#ifdef HAVE_IPV6 + case NEXTHOP_TYPE_IPV6: + if (nexthop_active_ipv6 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) + { + ifp = if_lookup_by_index (nexthop->ifindex); + if (ifp && if_is_up (ifp)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + else + { + if (nexthop_active_ipv6 (rib, nexthop, set, rn)) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + break; +#endif /* HAVE_IPV6 */ + default: + break; + } + return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); +} + +int +nexthop_active_update (struct route_node *rn, struct rib *rib, int set) +{ + struct nexthop *nexthop; + int active; + + rib->nexthop_active_num = 0; + UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + rib->nexthop_active_num += nexthop_active_check (rn, rib, nexthop, set); + if (active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + } + return rib->nexthop_active_num; +} + +#define RIB_SYSTEM_ROUTE(R) \ + ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) + +void +newrib_free (struct rib *rib) +{ + struct nexthop *nexthop; + struct nexthop *next; + + for (nexthop = rib->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + nexthop_free (nexthop); + } + XFREE (MTYPE_RIB, rib); +} + +void +rib_install_kernel (struct route_node *rn, struct rib *rib) +{ + int ret = 0; + struct nexthop *nexthop; + + switch (PREFIX_FAMILY (&rn->p)) + { + case AF_INET: + ret = kernel_add_ipv4 (&rn->p, rib); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = kernel_add_ipv6 (&rn->p, rib); + break; +#endif /* HAVE_IPV6 */ + } + + if (ret < 0) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + } +} + +/* Uninstall the route from kernel. */ +int +rib_uninstall_kernel (struct route_node *rn, struct rib *rib) +{ + int ret = 0; + struct nexthop *nexthop; + + switch (PREFIX_FAMILY (&rn->p)) + { + case AF_INET: + ret = kernel_delete_ipv4 (&rn->p, rib); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = kernel_delete_ipv6 (&rn->p, rib); + break; +#endif /* HAVE_IPV6 */ + } + + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + return ret; +} + +/* Uninstall the route from kernel. */ +void +rib_uninstall (struct route_node *rn, struct rib *rib) +{ + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + redistribute_delete (&rn->p, rib); + if (! RIB_SYSTEM_ROUTE (rib)) + rib_uninstall_kernel (rn, rib); + UNSET_FLAG (rib->flags, ZEBRA_FLAG_SELECTED); + } +} + +/* Core function for processing routing information base. */ +void +rib_process (struct route_node *rn, struct rib *del) +{ + struct rib *rib; + struct rib *next; + struct rib *fib = NULL; + struct rib *select = NULL; + + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + /* Currently installed rib. */ + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + /* Skip unreachable nexthop. */ + if (! nexthop_active_update (rn, rib, 0)) + continue; + + /* Infinit distance. */ + if (rib->distance == DISTANCE_INFINITY) + continue; + + /* Newly selected rib. */ + if (! select || rib->distance < select->distance + || rib->type == ZEBRA_ROUTE_CONNECT) + select = rib; + } + + /* Deleted route check. */ + if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED)) + fib = del; + + /* Same route is selected. */ + if (select && select == fib) + { + if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) + { + redistribute_delete (&rn->p, select); + if (! RIB_SYSTEM_ROUTE (select)) + rib_uninstall_kernel (rn, select); + + /* Set real nexthop. */ + nexthop_active_update (rn, select, 1); + + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + redistribute_add (&rn->p, select); + } + return; + } + + /* Uninstall old rib from forwarding table. */ + if (fib) + { + redistribute_delete (&rn->p, fib); + if (! RIB_SYSTEM_ROUTE (fib)) + rib_uninstall_kernel (rn, fib); + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + + /* Set real nexthop. */ + nexthop_active_update (rn, fib, 1); + } + + /* Install new rib into forwarding table. */ + if (select) + { + /* Set real nexthop. */ + nexthop_active_update (rn, select, 1); + + if (! RIB_SYSTEM_ROUTE (select)) + rib_install_kernel (rn, select); + SET_FLAG (select->flags, ZEBRA_FLAG_SELECTED); + redistribute_add (&rn->p, select); + } +} + +/* Add RIB to head of the route node. */ +void +rib_addnode (struct route_node *rn, struct rib *rib) +{ + struct rib *head; + + head = rn->info; + if (head) + head->prev = rib; + rib->next = head; + rn->info = rib; +} + +void +rib_delnode (struct route_node *rn, struct rib *rib) +{ + if (rib->next) + rib->next->prev = rib->prev; + if (rib->prev) + rib->prev->next = rib->next; + else + rn->info = rib->next; +} + +int +rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, int table, + u_int32_t metric, u_char distance) +{ + struct rib *rib; + struct rib *same = NULL; + struct route_node *rn; + struct nexthop *nexthop; + + /* Make it sure prefixlen is applied to the prefix. */ + apply_mask_ipv4 (p); + + /* Set default distance by route type. */ + if (distance == 0) + { + distance = route_info[type].distance; + + /* iBGP distance is 200. */ + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + } + + /* Lookup route node.*/ + rn = route_node_get (rib_table_ipv4, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + /* Duplicate connected route comes in. */ + if (rib->type == type + && (! table || rib->table == table) + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + rib->refcnt++; + return 0 ; + } + } + else if (rib->type == type + && (! table || rib->table == table)) + { + same = rib; + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* Allocate new rib structure. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + rib->type = type; + rib->distance = distance; + rib->flags = flags; + rib->metric = metric; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + /* Nexthop settings. */ + if (gate) + { + if (ifindex) + nexthop_ipv4_ifindex_add (rib, gate, ifindex); + else + nexthop_ipv4_add (rib, gate); + } + else + nexthop_ifindex_add (rib, ifindex); + + /* If this route is kernel route, set FIB flag to the route. */ + if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) +{ + struct route_node *rn; + struct rib *same; + struct nexthop *nexthop; + + /* 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 (rib_table_ipv4, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (same = rn->info; same; same = same->next) + { + if (same->type == rib->type && same->table == rib->table + && same->type != ZEBRA_ROUTE_CONNECT) + { + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* If this route is kernel route, set FIB flag to the route. */ + if (rib->type == ZEBRA_ROUTE_KERNEL || rib->type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, + struct in_addr *gate, unsigned int ifindex, int table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *fib = NULL; + struct rib *same = NULL; + struct nexthop *nexthop; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + /* Apply mask. */ + apply_mask_ipv4 (p); + + /* Lookup route node. */ + rn = route_node_lookup (rib_table_ipv4, (struct prefix *) p); + if (! rn) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET, gate, buf2, BUFSIZ), + ifindex); + else + zlog_info ("route %s/%d ifindex %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex); + } + return ZEBRA_ERR_RTNOEXIST; + } + + /* Lookup same type route. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && (! table || rib->table == table) + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + if (rib->refcnt) + { + rib->refcnt--; + route_unlock_node (rn); + route_unlock_node (rn); + return 0; + } + same = rib; + break; + } + } + else + { + if (rib->type == type + && (!table || rib->table == table)) + { + same = rib; + break; + } + } + } + + /* If same type of route can't be found and this message is from + kernel. */ + if (! same) + { + if (fib && type == ZEBRA_ROUTE_KERNEL) + { + /* Unset flags. */ + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET, gate, buf2, BUFSIZ), + ifindex, + type); + else + zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex, + type); + } + route_unlock_node (rn); + return ZEBRA_ERR_RTNOEXIST; + } + } + + if (same) + rib_delnode (rn, same); + + /* Process changes. */ + rib_process (rn, same); + + if (same) + { + newrib_free (same); + route_unlock_node (rn); + } + + route_unlock_node (rn); + + return 0; +} + +/* Delete all added route and close rib. */ +void +rib_close_ipv4 () +{ + struct route_node *rn; + struct rib *rib; + + for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (! RIB_SYSTEM_ROUTE (rib) + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + rib_uninstall_kernel (rn, rib); +} + +/* Install static route into rib. */ +void +static_ipv4_install (struct prefix_ipv4 *p, struct static_ipv4 *si) +{ + struct rib *rib; + struct route_node *rn; + + /* Lookup existing route */ + rn = route_node_get (rib_table_ipv4, (struct prefix *) p); + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (rib) + { + /* Same distance static route is there. Update it with new + nexthop. */ + rib_uninstall (rn, rib); + route_unlock_node (rn); + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->gate.ipv4); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->gate.ifname); + break; + } + rib_process (rn, NULL); + } + else + { + /* This is new static route. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + + rib->type = ZEBRA_ROUTE_STATIC; + rib->distance = si->distance; + rib->metric = 0; + rib->nexthop_num = 0; + + switch (si->type) + { + case STATIC_IPV4_GATEWAY: + nexthop_ipv4_add (rib, &si->gate.ipv4); + break; + case STATIC_IPV4_IFNAME: + nexthop_ifname_add (rib, si->gate.ifname); + break; + } + + /* Link this rib to the tree. */ + rib_addnode (rn, rib); + + /* Process this prefix. */ + rib_process (rn, NULL); + } +} + +int +static_ipv4_nexthop_same (struct nexthop *nexthop, struct static_ipv4 *si) +{ + if (nexthop->type == NEXTHOP_TYPE_IPV4 + && si->type == STATIC_IPV4_GATEWAY + && IPV4_ADDR_SAME (&nexthop->gate.ipv4, &si->gate.ipv4)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFNAME + && si->type == STATIC_IPV4_IFNAME + && strcmp (nexthop->ifname, si->gate.ifname) == 0) + return 1; + return 0;; +} + +/* Uninstall static route from RIB. */ +void +static_ipv4_uninstall (struct prefix_ipv4 *p, struct static_ipv4 *si) +{ + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; + + /* Lookup existing route with type and distance. */ + rn = route_node_lookup (rib_table_ipv4, (struct prefix *) p); + if (! rn) + return; + + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + if (! rib) + { + route_unlock_node (rn); + return; + } + + /* Lookup nexthop. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (static_ipv4_nexthop_same (nexthop, si)) + break; + + /* Can't find nexthop. */ + if (! nexthop) + { + route_unlock_node (rn); + return; + } + + /* Check nexthop. */ + if (rib->nexthop_num == 1) + { + rib_delnode (rn, rib); + rib_process (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + else + { + rib_uninstall (rn, rib); + nexthop_delete (rib, nexthop); + nexthop_free (nexthop); + rib_process (rn, rib); + } + + /* Unlock node. */ + route_unlock_node (rn); +} + +/* Add static route into static route configuration. */ +int +static_ipv4_add (struct prefix_ipv4 *p, struct in_addr *gate, char *ifname, + u_char distance, int table) +{ + u_char type = 0; + struct route_node *rn; + struct static_ipv4 *si; + struct static_ipv4 *pp; + struct static_ipv4 *cp; + + /* Lookup static route prefix. */ + rn = route_node_get (static_table_ipv4, (struct prefix *) p); + + /* Make flags. */ + if (gate) + type = STATIC_IPV4_GATEWAY; + if (ifname) + type = STATIC_IPV4_IFNAME; + + /* 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 || IPV4_ADDR_SAME (gate, &si->gate.ipv4)) + && (! ifname || strcmp (ifname, si->gate.ifname) == 0)) + { + route_unlock_node (rn); + return 0; + } + } + + /* Make new static route structure. */ + si = XMALLOC (MTYPE_STATIC_IPV4, sizeof (struct static_ipv4)); + memset (si, 0, sizeof (struct static_ipv4)); + + si->type = type; + si->distance = distance; + + if (gate) + si->gate.ipv4 = *gate; + if (ifname) + si->gate.ifname = XSTRDUP (0, ifname); + + /* Add new static route information to the tree with sort by + distance value and gateway address. */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) + { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + if (si->type == STATIC_IPV4_GATEWAY && cp->type == STATIC_IPV4_GATEWAY) + { + if (ntohl (si->gate.ipv4.s_addr) < ntohl (cp->gate.ipv4.s_addr)) + break; + if (ntohl (si->gate.ipv4.s_addr) > ntohl (cp->gate.ipv4.s_addr)) + continue; + } + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* Install into rib. */ + static_ipv4_install (p, si); + + return 1; +} + +/* Delete static route from static route configuration. */ +int +static_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *gate, char *ifname, + u_char distance, int table) +{ + u_char type = 0; + struct route_node *rn; + struct static_ipv4 *si; + + /* Lookup static route prefix. */ + rn = route_node_lookup (static_table_ipv4, (struct prefix *) p); + if (! rn) + return 0; + + /* Make flags. */ + if (gate) + type = STATIC_IPV4_GATEWAY; + if (ifname) + type = STATIC_IPV4_IFNAME; + + /* Find same static route is the tree */ + for (si = rn->info; si; si = si->next) + if (distance == si->distance + && 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_ipv4_uninstall (p, si); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + + /* Free static route configuration. */ + XFREE (MTYPE_STATIC_IPV4, si); + + return 1; +} + +/* Write IPv4 static route configuration. */ +int +static_ipv4_write (struct vty *vty) +{ + struct route_node *rn; + struct static_ipv4 *si; + int write; + + write = 0; + + for (rn = route_top (static_table_ipv4); 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; + } + + if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + return write; +} + +/* General fucntion for static route. */ +int +static_ipv4_func (struct vty *vty, int add_cmd, + char *dest_str, char *mask_str, char *gate_str, + char *distance_str) +{ + int ret; + u_char distance; + struct prefix_ipv4 p; + struct in_addr gate; + struct in_addr mask; + char *ifname; + int table = rtm_table_default; + + ret = str2prefix_ipv4 (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_ipv4 (&p); + + /* Administrative distance. */ + if (distance_str) + distance = atoi (distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* 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_ipv4_add (&p, ifname ? NULL : &gate, ifname, distance, table); + else + static_ipv4_delete (&p, ifname ? NULL : &gate, ifname, distance, table); + + return CMD_SUCCESS; +} + +/* Static route configuration. */ +DEFUN (ip_route, + ip_route_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE)", + 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") +{ + return static_ipv4_func (vty, 1, argv[0], NULL, argv[1], NULL); +} + +DEFUN (ip_route_mask, + ip_route_mask_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)", + IP_STR + "Establish static routes\n" + "IP destination prefix\n" + "IP destination prefix mask\n" + "IP gateway address\n" + "IP gateway interface name\n") +{ + return static_ipv4_func (vty, 1, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (ip_route_pref, + ip_route_pref_cmd, + "ip route A.B.C.D/M (A.B.C.D|INTERFACE) <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" + "Distance value for this route\n") +{ + return static_ipv4_func (vty, 1, argv[0], NULL, argv[1], argv[2]); +} + +DEFUN (ip_route_mask_pref, + ip_route_mask_pref_cmd, + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <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") +{ + return static_ipv4_func (vty, 1, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_ip_route, + no_ip_route_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE)", + 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") +{ + return static_ipv4_func (vty, 0, argv[0], NULL, argv[1], NULL); +} + +DEFUN (no_ip_route_mask, + no_ip_route_mask_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE)", + 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") +{ + return static_ipv4_func (vty, 0, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_ip_route_pref, + no_ip_route_pref_cmd, + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) <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" + "Distance value for this route\n") +{ + return static_ipv4_func (vty, 0, argv[0], NULL, argv[1], argv[2]); +} + +DEFUN (no_ip_route_mask_pref, + no_ip_route_mask_pref_cmd, + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) <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" + "Distance value for this route\n") +{ + return static_ipv4_func (vty, 0, argv[0], argv[1], argv[2], argv[3]); +} + +/* New RIB. Detailed information for IPv4 route. */ +void +vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) +{ + struct rib *rib; + struct nexthop *nexthop; + + for (rib = rn->info; rib; rib = rib->next) + { + vty_out (vty, "Routing entry for %s/%d%s", + inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, + VTY_NEWLINE); + vty_out (vty, " Known via \"%s\"", route_info[rib->type].str); + vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + vty_out (vty, ", best"); + if (rib->refcnt) + vty_out (vty, ", refcnt %ld", rib->refcnt); + vty_out (vty, "%s", VTY_NEWLINE); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_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_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; + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + vty_out (vty, "%s", VTY_NEWLINE); + } + vty_out (vty, "%s", VTY_NEWLINE); + } +} + +void +vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) +{ + struct nexthop *nexthop; + int len = 0; + char buf[BUFSIZ]; + + /* Nexthop information. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (nexthop == rib->nexthop) + { + /* Prefix information. */ + len = vty_out (vty, "%c%c%c %s/%d", + route_info[rib->type].c, + 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; + default: + break; + } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out (vty, " inactive"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + { + vty_out (vty, " (recursive"); + + switch (nexthop->rtype) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out (vty, " via %s)", inet_ntoa (nexthop->rgate.ipv4)); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_IFNAME: + vty_out (vty, " is directly connected, %s)", + ifindex2ifname (nexthop->rifindex)); + break; + default: + break; + } + } + + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_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); + } +} + +#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,%s I - IS-IS, %s B - BGP, > - selected route, * - FIB route%s%s" + +DEFUN (show_ip_route, + show_ip_route_cmd, + "show ip route", + SHOW_STR + IP_STR + "IP routing table\n") +{ + struct route_node *rn; + struct rib *rib; + int first = 1; + + /* Show all IPv4 routes. */ + for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_prefix_longer, + show_ip_route_prefix_longer_cmd, + "show ip route A.B.C.D/M longer-prefixes", + SHOW_STR + IP_STR + "IP routing table\n" + "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n" + "Show route matching the specified Network/Mask pair only\n") +{ + 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; + } + + /* Show matched type IPv4 routes. */ + for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_supernets, + show_ip_route_supernets_cmd, + "show ip route supernets-only", + SHOW_STR + IP_STR + "IP routing table\n" + "Show supernet entries only\n") +{ + struct route_node *rn; + struct rib *rib; + u_int32_t addr; + int first = 1; + + + /* Show matched type IPv4 routes. */ + for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + addr = ntohl (rn->p.u.prefix4.s_addr); + + if ((IN_CLASSC (addr) && rn->p.prefixlen < 24) + || (IN_CLASSB (addr) && rn->p.prefixlen < 16) + || (IN_CLASSA (addr) && rn->p.prefixlen < 8)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + } + return CMD_SUCCESS; +} + + +DEFUN (show_ip_route_protocol, + show_ip_route_protocol_cmd, + "show ip route (bgp|connected|kernel|ospf|isis|rip|static)", + SHOW_STR + IP_STR + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPF)\n" + "ISO IS-IS (ISIS)\n" + "Routing Information Protocol (RIP)\n" + "Static routes\n") +{ + int type; + struct route_node *rn; + struct rib *rib; + int first = 1; + + if (strncmp (argv[0], "b", 1) == 0) + type = ZEBRA_ROUTE_BGP; + else if (strncmp (argv[0], "c", 1) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "k", 1) ==0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "o", 1) == 0) + type = ZEBRA_ROUTE_OSPF; + else if (strncmp (argv[0], "i", 1) == 0) + type = ZEBRA_ROUTE_ISIS; + else if (strncmp (argv[0], "r", 1) == 0) + type = ZEBRA_ROUTE_RIP; + else if (strncmp (argv[0], "s", 1) == 0) + type = ZEBRA_ROUTE_STATIC; + else + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Show matched type IPv4 routes. */ + for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, + VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ip_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ip_route_addr, + show_ip_route_addr_cmd, + "show ip route A.B.C.D", + SHOW_STR + IP_STR + "IP routing table\n" + "Network in the IP routing table to display\n") +{ + int ret; + struct prefix_ipv4 p; + struct route_node *rn; + + ret = str2prefix_ipv4 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv4 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_match (rib_table_ipv4, (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 <network>/<length>, e.g., 35.0.0.0/8\n") +{ + int ret; + struct prefix_ipv4 p; + 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; + } + + rn = route_node_match (rib_table_ipv4, (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; +} + +#ifdef HAVE_IPV6 +int +rib_bogus_ipv6 (int type, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, int table) +{ + if (type == ZEBRA_ROUTE_CONNECT && IN6_IS_ADDR_UNSPECIFIED (&p->prefix)) + return 1; + if (type == ZEBRA_ROUTE_KERNEL && IN6_IS_ADDR_UNSPECIFIED (&p->prefix) + && p->prefixlen == 96 && gate && IN6_IS_ADDR_UNSPECIFIED (gate)) + { + kernel_delete_ipv6_old (p, gate, ifindex, 0, table); + return 1; + } + return 0; +} + +int +rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, int table) +{ + struct rib *rib; + struct rib *same = NULL; + struct route_node *rn; + struct nexthop *nexthop; + + int distance; + u_int32_t metric = 0; + + /* Make sure mask is applied. */ + apply_mask_ipv6 (p); + + /* Set default distance by route type. */ + distance = route_info[type].distance; + + if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) + distance = 200; + + /* Make new rib. */ + if (!table) + table = RT_TABLE_MAIN; + + /* Filter bogus route. */ + if (rib_bogus_ipv6 (type, p, gate, ifindex, table)) + return 0; + + /* Lookup route node.*/ + rn = route_node_get (rib_table_ipv6, (struct prefix *) p); + + /* If same type of route are installed, treat it as a implicit + withdraw. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && (! table || rib->table == table) + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + rib->refcnt++; + return 0; + } + } + else if (rib->type == type + && (! table || (rib->table == table))) + { + same = rib; + rib_delnode (rn, same); + route_unlock_node (rn); + break; + } + } + + /* Allocate new rib structure. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + rib->type = type; + rib->distance = distance; + rib->flags = flags; + rib->metric = metric; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + /* Nexthop settings. */ + if (gate) + { + if (ifindex) + nexthop_ipv6_ifindex_add (rib, gate, ifindex); + else + nexthop_ipv6_add (rib, gate); + } + else + nexthop_ifindex_add (rib, ifindex); + + /* If this route is kernel route, set FIB flag to the route. */ + if (type == ZEBRA_ROUTE_KERNEL || type == ZEBRA_ROUTE_CONNECT) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + /* Link new rib to node.*/ + rib_addnode (rn, rib); + + /* Process this route node. */ + rib_process (rn, same); + + /* Free implicit route.*/ + if (same) + newrib_free (same); + + return 0; +} + +int +rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, + struct in6_addr *gate, unsigned int ifindex, int table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *fib = NULL; + struct rib *same = NULL; + struct nexthop *nexthop; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + /* Apply mask. */ + apply_mask_ipv6 (p); + + /* Lookup route node. */ + rn = route_node_lookup (rib_table_ipv6, (struct prefix *) p); + if (! rn) + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + ifindex); + else + zlog_info ("route %s/%d ifindex %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex); + } + return ZEBRA_ERR_RTNOEXIST; + } + + /* Lookup same type route. */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + fib = rib; + + if (rib->type == ZEBRA_ROUTE_CONNECT) + { + nexthop = rib->nexthop; + + if (rib->type == type + && (! table || rib->table == table) + && nexthop && nexthop->type == NEXTHOP_TYPE_IFINDEX + && nexthop->ifindex == ifindex) + { + if (rib->refcnt) + { + rib->refcnt--; + route_unlock_node (rn); + route_unlock_node (rn); + return 0; + } + same = rib; + break; + } + } + else + { + if (rib->type == type + && (! table || rib->table == table)) + { + same = rib; + break; + } + } + } + + /* If same type of route can't be found and this message is from + kernel. */ + if (! same) + { + if (fib && type == ZEBRA_ROUTE_KERNEL) + { + /* Unset flags. */ + for (nexthop = fib->nexthop; nexthop; nexthop = nexthop->next) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); + + UNSET_FLAG (fib->flags, ZEBRA_FLAG_SELECTED); + } + else + { + if (IS_ZEBRA_DEBUG_KERNEL) + { + if (gate) + zlog_info ("route %s/%d via %s ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntop (AF_INET6, gate, buf2, BUFSIZ), + ifindex, + type); + else + zlog_info ("route %s/%d ifindex %d type %d doesn't exist in rib", + inet_ntop (AF_INET6, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex, + type); + } + route_unlock_node (rn); + return ZEBRA_ERR_RTNOEXIST; + } + } + + if (same) + rib_delnode (rn, same); + + /* Process changes. */ + rib_process (rn, same); + + if (same) + { + newrib_free (same); + route_unlock_node (rn); + } + + route_unlock_node (rn); + + return 0; +} + +/* Delete non system routes. */ +void +rib_close_ipv6 () +{ + struct route_node *rn; + struct rib *rib; + + for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (! RIB_SYSTEM_ROUTE (rib) + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + rib_uninstall_kernel (rn, rib); +} + +/* Install static route into rib. */ +void +static_ipv6_install (struct prefix_ipv6 *p, struct static_ipv6 *si) +{ + struct rib *rib; + struct route_node *rn; + + /* Lookup existing route */ + rn = route_node_get (rib_table_ipv6, (struct prefix *) p); + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + + if (rib) + { + /* Same distance static route is there. Update it with new + nexthop. */ + rib_uninstall (rn, rib); + route_unlock_node (rn); + + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + break; + } + rib_process (rn, NULL); + } + else + { + /* This is new static route. */ + rib = XMALLOC (MTYPE_RIB, sizeof (struct rib)); + memset (rib, 0, sizeof (struct rib)); + + rib->type = ZEBRA_ROUTE_STATIC; + rib->distance = si->distance; + rib->metric = 0; + rib->nexthop_num = 0; + + switch (si->type) + { + case STATIC_IPV6_GATEWAY: + nexthop_ipv6_add (rib, &si->ipv6); + break; + case STATIC_IPV6_IFNAME: + nexthop_ifname_add (rib, si->ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); + break; + } + + /* Link this rib to the tree. */ + rib_addnode (rn, rib); + + /* Process this prefix. */ + rib_process (rn, NULL); + } +} + +int +static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) +{ + if (nexthop->type == NEXTHOP_TYPE_IPV6 + && si->type == STATIC_IPV6_GATEWAY + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6)) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IFNAME + && si->type == STATIC_IPV6_IFNAME + && strcmp (nexthop->ifname, si->ifname) == 0) + return 1; + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME + && si->type == STATIC_IPV6_GATEWAY_IFNAME + && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) + && strcmp (nexthop->ifname, si->ifname) == 0) + return 1; + return 0;; +} + +void +static_ipv6_uninstall (struct prefix_ipv6 *p, struct static_ipv6 *si) +{ + struct route_node *rn; + struct rib *rib; + struct nexthop *nexthop; + + /* Lookup existing route with type and distance. */ + rn = route_node_lookup (rib_table_ipv6, (struct prefix *) p); + if (! rn) + return; + + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + if (! rib) + { + route_unlock_node (rn); + return; + } + + /* Lookup nexthop. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (static_ipv6_nexthop_same (nexthop, si)) + break; + + /* Can't find nexthop. */ + if (! nexthop) + { + route_unlock_node (rn); + return; + } + + /* Check nexthop. */ + if (rib->nexthop_num == 1) + { + rib_delnode (rn, rib); + rib_process (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + else + { + rib_uninstall (rn, rib); + nexthop_delete (rib, nexthop); + nexthop_free (nexthop); + rib_process (rn, rib); + } + + /* Unlock node. */ + route_unlock_node (rn); +} + +/* Add static route into static route configuration. */ +int +static_ipv6_add (struct prefix_ipv6 *p, u_char type, struct in6_addr *gate, + char *ifname, u_char distance, int table) +{ + struct route_node *rn; + struct static_ipv6 *si; + struct static_ipv6 *pp; + struct static_ipv6 *cp; + + /* Lookup static route prefix. */ + rn = route_node_get (static_table_ipv6, (struct prefix *) p); + + /* Do nothing if there is a same static route. */ + for (si = rn->info; si; si = si->next) + { + if (distance == si->distance + && type == si->type + && (! gate || IPV6_ADDR_SAME (gate, &si->ipv6)) + && (! ifname || strcmp (ifname, si->ifname) == 0)) + { + route_unlock_node (rn); + return 0; + } + } + + /* Make new static route structure. */ + si = XMALLOC (MTYPE_STATIC_IPV6, sizeof (struct static_ipv6)); + memset (si, 0, sizeof (struct static_ipv6)); + + si->type = type; + si->distance = distance; + + switch (type) + { + case STATIC_IPV6_GATEWAY: + si->ipv6 = *gate; + break; + case STATIC_IPV6_IFNAME: + si->ifname = XSTRDUP (0, ifname); + break; + case STATIC_IPV6_GATEWAY_IFNAME: + si->ipv6 = *gate; + si->ifname = XSTRDUP (0, ifname); + break; + } + + /* Add new static route information to the tree with sort by + distance value and gateway address. */ + for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) + { + if (si->distance < cp->distance) + break; + if (si->distance > cp->distance) + continue; + } + + /* Make linked list. */ + if (pp) + pp->next = si; + else + rn->info = si; + if (cp) + cp->prev = si; + si->prev = pp; + si->next = cp; + + /* Install into rib. */ + static_ipv6_install (p, si); + + return 1; +} + +/* Delete static route from static route configuration. */ +int +static_ipv6_delete (struct prefix_ipv6 *p, u_char type, struct in6_addr *gate, + char *ifname, u_char distance, int table) +{ + struct route_node *rn; + struct static_ipv6 *si; + + /* Lookup static route prefix. */ + rn = route_node_lookup (static_table_ipv6, (struct prefix *) 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_ipv6_uninstall (p, si); + + /* Unlink static route from linked list. */ + if (si->prev) + si->prev->next = si->next; + else + rn->info = si->next; + if (si->next) + si->next->prev = si->prev; + + /* Free static route configuration. */ + XFREE (MTYPE_STATIC_IPV6, si); + + return 1; +} + +/* General fucntion for IPv6 static route. */ +int +static_ipv6_func (struct vty *vty, int add_cmd, char *dest_str, + char *gate_str, char *ifname, char *distance_str) +{ + int ret; + u_char distance; + struct prefix_ipv6 p; + struct in6_addr *gate = NULL; + struct in6_addr gate_addr; + u_char type = 0; + int table = rtm_table_default; + + ret = str2prefix_ipv6 (dest_str, &p); + if (ret <= 0) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Apply mask for given prefix. */ + apply_mask_ipv6 (&p); + + /* Administrative distance. */ + if (distance_str) + distance = atoi (distance_str); + else + distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + + /* When gateway is valid IPv6 addrees, then gate is treated as + nexthop address other case gate is treated as interface name. */ + ret = inet_pton (AF_INET6, gate_str, &gate_addr); + + if (ifname) + { + /* When ifname is specified. It must be come with gateway + address. */ + if (ret != 1) + { + vty_out (vty, "%% Malformed address%s", VTY_NEWLINE); + return CMD_WARNING; + } + type = STATIC_IPV6_GATEWAY_IFNAME; + gate = &gate_addr; + } + else + { + if (ret == 1) + { + type = STATIC_IPV6_GATEWAY; + gate = &gate_addr; + } + else + { + type = STATIC_IPV6_IFNAME; + ifname = gate_str; + } + } + + if (add_cmd) + static_ipv6_add (&p, type, gate, ifname, distance, table); + else + static_ipv6_delete (&p, type, gate, ifname, distance, table); + + return CMD_SUCCESS; +} + +/* Write IPv6 static route configuration. */ +int +static_ipv6_write (struct vty *vty) +{ + struct route_node *rn; + struct static_ipv6 *si; + int write; + char buf[BUFSIZ]; + + write = 0; + + for (rn = route_top (static_table_ipv6); 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 (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) + vty_out (vty, " %d", si->distance); + vty_out (vty, "%s", VTY_NEWLINE); + + write = 1; + } + return write; +} + +DEFUN (ipv6_route, + ipv6_route_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL); +} + +DEFUN (ipv6_route_ifname, + ipv6_route_ifname_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (ipv6_route_pref, + ipv6_route_pref_cmd, + "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2]); +} + +DEFUN (ipv6_route_ifname_pref, + ipv6_route_ifname_pref_cmd, + "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3]); +} + +DEFUN (no_ipv6_route, + no_ipv6_route_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL); +} + +DEFUN (no_ipv6_route_ifname, + no_ipv6_route_ifname_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL); +} + +DEFUN (no_ipv6_route_pref, + no_ipv6_route_pref_cmd, + "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2]); +} + +DEFUN (no_ipv6_route_ifname_pref, + no_ipv6_route_ifname_pref_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "IPv6 gateway address\n" + "IPv6 gateway interface name\n" + "Distance value for this prefix\n") +{ + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3]); +} + +/* New RIB. Detailed information for IPv4 route. */ +void +vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) +{ + struct rib *rib; + struct nexthop *nexthop; + char buf[BUFSIZ]; + + for (rib = rn->info; rib; rib = rib->next) + { + vty_out (vty, "Routing entry for %s/%d%s", + inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), + rn->p.prefixlen, + VTY_NEWLINE); + vty_out (vty, " Known via \"%s\"", route_info[rib->type].str); + vty_out (vty, ", distance %d, metric %d", rib->distance, rib->metric); + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + vty_out (vty, ", best"); + if (rib->refcnt) + vty_out (vty, ", refcnt %ld", rib->refcnt); + vty_out (vty, "%s", VTY_NEWLINE); + +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + if (rib->type == ZEBRA_ROUTE_RIPNG + || rib->type == ZEBRA_ROUTE_OSPF6 + || rib->type == ZEBRA_ROUTE_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); + } +} + +void +vty_show_ipv6_route (struct vty *vty, struct route_node *rn, + struct rib *rib) +{ + struct nexthop *nexthop; + int len = 0; + char buf[BUFSIZ]; + + /* Nexthop information. */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + if (nexthop == rib->nexthop) + { + /* Prefix information. */ + len = vty_out (vty, "%c%c%c %s/%d", + route_info[rib->type].c, + 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 (rib->type == ZEBRA_ROUTE_RIPNG + || rib->type == ZEBRA_ROUTE_OSPF6 + || 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); + } +} + +#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3, I - IS-IS,%s B - BGP, * - FIB route.%s%s" + +DEFUN (show_ipv6_route, + show_ipv6_route_cmd, + "show ipv6 route", + SHOW_STR + IP_STR + "IPv6 routing table\n") +{ + struct route_node *rn; + struct rib *rib; + int first = 1; + + /* Show all IPv6 route. */ + for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_prefix_longer, + show_ipv6_route_prefix_longer_cmd, + "show ipv6 route X:X::X:X/M longer-prefixes", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 prefix\n" + "Show route matching the specified Network/Mask pair only\n") +{ + struct route_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; + } + + /* Show matched type IPv6 routes. */ + for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (prefix_match (&p, &rn->p)) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + +DEFUN (show_ipv6_route_protocol, + show_ipv6_route_protocol_cmd, + "show ipv6 route (bgp|connected|kernel|ospf6|isis|ripng|static)", + SHOW_STR + IP_STR + "IP routing table\n" + "Border Gateway Protocol (BGP)\n" + "Connected\n" + "Kernel\n" + "Open Shortest Path First (OSPFv3)\n" + "ISO IS-IS (ISIS)\n" + "Routing Information Protocol (RIPng)\n" + "Static routes\n") +{ + int type; + struct route_node *rn; + struct rib *rib; + int first = 1; + + if (strncmp (argv[0], "b", 1) == 0) + type = ZEBRA_ROUTE_BGP; + else if (strncmp (argv[0], "c", 1) == 0) + type = ZEBRA_ROUTE_CONNECT; + else if (strncmp (argv[0], "k", 1) ==0) + type = ZEBRA_ROUTE_KERNEL; + else if (strncmp (argv[0], "o", 1) == 0) + type = ZEBRA_ROUTE_OSPF6; + else if (strncmp (argv[0], "i", 1) == 0) + type = ZEBRA_ROUTE_ISIS; + else if (strncmp (argv[0], "r", 1) == 0) + type = ZEBRA_ROUTE_RIPNG; + else if (strncmp (argv[0], "s", 1) == 0) + type = ZEBRA_ROUTE_STATIC; + else + { + vty_out (vty, "Unknown route type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* Show matched type IPv6 routes. */ + for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = rib->next) + if (rib->type == type) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + first = 0; + } + vty_show_ipv6_route (vty, rn, rib); + } + return CMD_SUCCESS; +} + + +DEFUN (show_ipv6_route_addr, + show_ipv6_route_addr_cmd, + "show ipv6 route X:X::X:X", + SHOW_STR + IP_STR + "IPv6 routing table\n" + "IPv6 Address\n") +{ + int ret; + struct prefix_ipv6 p; + struct route_node *rn; + + ret = str2prefix_ipv6 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_match (rib_table_ipv6, (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_node *rn; + + ret = str2prefix_ipv6 (argv[0], &p); + if (ret <= 0) + { + vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rn = route_node_match (rib_table_ipv6, (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; +} +#endif /* HAVE_IPV6 */ + +/* RIB update function. */ +void +rib_update () +{ + struct route_node *rn; + + for (rn = route_top (rib_table_ipv4); rn; rn = route_next (rn)) + /* Update reachability. */ + rib_process (rn, NULL); + +#ifdef HAVE_IPV6 + for (rn = route_top (rib_table_ipv6); rn; rn = route_next (rn)) + rib_process (rn, NULL); +#endif /* HAVE_IPV6 */ +} + +/* Interface goes up. */ +void +rib_if_up (struct interface *ifp) +{ + rib_update (); +} + +/* Interface goes down. */ +void +rib_if_down (struct interface *ifp) +{ + rib_update (); +} + +/* Clean up routines. */ +void +rib_weed_table (struct route_table *rib_table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + + for (rn = route_top (rib_table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (rib->table != rtm_table_default && + rib->table != RT_TABLE_MAIN) + { + rib_delnode (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + } +} + +/* Delete all routes from unmanaged tables. */ +void +rib_weed_tables () +{ + rib_weed_table (rib_table_ipv4); +#ifdef HAVE_IPV6 + rib_weed_table (rib_table_ipv6); +#endif /* HAVE_IPV6 */ +} + +void +rib_sweep_table (struct route_table *rib_table) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + int ret = 0; + + for (rn = route_top (rib_table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if ((rib->type == ZEBRA_ROUTE_KERNEL) && + CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) + { + ret = rib_uninstall_kernel (rn, rib); + + if (! ret) + { + rib_delnode (rn, rib); + newrib_free (rib); + route_unlock_node (rn); + } + } + } +} + +void +rib_sweep_route () +{ + rib_sweep_table (rib_table_ipv4); +#ifdef HAVE_IPV6 + rib_sweep_table (rib_table_ipv6); +#endif /* HAVE_IPV6 */ +} + +/* Close rib when zebra terminates. */ +void +rib_close () +{ + rib_close_ipv4 (); +#ifdef HAVE_IPV6 + rib_close_ipv6 (); +#endif /* HAVE_IPV6 */ +} + +/* Static ip route configuration write function. */ +int +config_write_ip (struct vty *vty) +{ + int write = 0; + + write += static_ipv4_write (vty); +#ifdef HAVE_IPV6 + write += static_ipv6_write (vty); +#endif /* HAVE_IPV6 */ + + return write; +} + +/* IP node for static routes. */ +struct cmd_node ip_node = +{ + IP_NODE, + "", /* This node has no interface. */ + 1 +}; + +/* Routing information base initialize. */ +void +rib_init () +{ + install_node (&ip_node, config_write_ip); + + rib_table_ipv4 = route_table_init (); + static_table_ipv4 = route_table_init (); + + install_element (VIEW_NODE, &show_ip_route_cmd); + install_element (VIEW_NODE, &show_ip_route_addr_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_cmd); + install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd); + install_element (VIEW_NODE, &show_ip_route_protocol_cmd); + install_element (VIEW_NODE, &show_ip_route_supernets_cmd); + install_element (ENABLE_NODE, &show_ip_route_cmd); + install_element (ENABLE_NODE, &show_ip_route_addr_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_cmd); + install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ip_route_protocol_cmd); + install_element (ENABLE_NODE, &show_ip_route_supernets_cmd); + install_element (CONFIG_NODE, &ip_route_cmd); + install_element (CONFIG_NODE, &ip_route_mask_cmd); + install_element (CONFIG_NODE, &no_ip_route_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_cmd); + install_element (CONFIG_NODE, &ip_route_pref_cmd); + install_element (CONFIG_NODE, &ip_route_mask_pref_cmd); + install_element (CONFIG_NODE, &no_ip_route_pref_cmd); + install_element (CONFIG_NODE, &no_ip_route_mask_pref_cmd); + +#ifdef HAVE_IPV6 + rib_table_ipv6 = route_table_init (); + static_table_ipv6 = route_table_init (); + + install_element (CONFIG_NODE, &ipv6_route_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd); + install_element (CONFIG_NODE, &ipv6_route_pref_cmd); + install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd); + install_element (VIEW_NODE, &show_ipv6_route_cmd); + install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); + install_element (VIEW_NODE, &show_ipv6_route_addr_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd); + install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd); + install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/isisd/modified/thread.c b/isisd/modified/thread.c new file mode 100644 index 00000000..af954b83 --- /dev/null +++ b/isisd/modified/thread.c @@ -0,0 +1,713 @@ +/* Thread management routine + * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU 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 <zebra.h> + +#include "thread.h" +#include "memory.h" +#include "log.h" + +/* Struct timeval's tv_usec one second value. */ +#define TIMER_SECOND_MICRO 1000000L + +struct timeval +timeval_adjust (struct timeval a) +{ + while (a.tv_usec >= TIMER_SECOND_MICRO) + { + a.tv_usec -= TIMER_SECOND_MICRO; + a.tv_sec++; + } + + while (a.tv_usec < 0) + { + a.tv_usec += TIMER_SECOND_MICRO; + a.tv_sec--; + } + + if (a.tv_sec < 0) + { + a.tv_sec = 0; + a.tv_usec = 10; + } + + if (a.tv_sec > TIMER_SECOND_MICRO) + a.tv_sec = TIMER_SECOND_MICRO; + + return a; +} + +static struct timeval +timeval_subtract (struct timeval a, struct timeval b) +{ + struct timeval ret; + + ret.tv_usec = a.tv_usec - b.tv_usec; + ret.tv_sec = a.tv_sec - b.tv_sec; + + return timeval_adjust (ret); +} + +static int +timeval_cmp (struct timeval a, struct timeval b) +{ + return (a.tv_sec == b.tv_sec + ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); +} + +static unsigned long +timeval_elapsed (struct timeval a, struct timeval b) +{ + return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + + (a.tv_usec - b.tv_usec)); +} + +/* List allocation and head/tail print out. */ +static void +thread_list_debug (struct thread_list *list) +{ + printf ("count [%d] head [%p] tail [%p]\n", + list->count, list->head, list->tail); +} + +/* Debug print for thread_master. */ +void +thread_master_debug (struct thread_master *m) +{ + printf ("-----------\n"); + printf ("readlist : "); + thread_list_debug (&m->read); + printf ("writelist : "); + thread_list_debug (&m->write); + printf ("timerlist : "); + thread_list_debug (&m->timer); + printf ("eventlist : "); + thread_list_debug (&m->event); + printf ("unuselist : "); + thread_list_debug (&m->unuse); + printf ("total alloc: [%ld]\n", m->alloc); + printf ("-----------\n"); +} + +/* Allocate new thread master. */ +struct thread_master * +thread_master_create () +{ + return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER, + sizeof (struct thread_master)); +} + +/* Add a new thread to the list. */ +static void +thread_list_add (struct thread_list *list, struct thread *thread) +{ + thread->next = NULL; + thread->prev = list->tail; + if (list->tail) + list->tail->next = thread; + else + list->head = thread; + list->tail = thread; + list->count++; +} + +/* Add a new thread just before the point. */ +static void +thread_list_add_before (struct thread_list *list, + struct thread *point, + struct thread *thread) +{ + thread->next = point; + thread->prev = point->prev; + if (point->prev) + point->prev->next = thread; + else + list->head = thread; + point->prev = thread; + list->count++; +} + +/* Delete a thread from the list. */ +static struct thread * +thread_list_delete (struct thread_list *list, struct thread *thread) +{ + if (thread->next) + thread->next->prev = thread->prev; + else + list->tail = thread->prev; + if (thread->prev) + thread->prev->next = thread->next; + else + list->head = thread->next; + thread->next = thread->prev = NULL; + list->count--; + return thread; +} + +/* Move thread to unuse list. */ +static void +thread_add_unuse (struct thread_master *m, struct thread *thread) +{ + assert (m != NULL); + assert (thread->next == NULL); + assert (thread->prev == NULL); + assert (thread->type == THREAD_UNUSED); + thread_list_add (&m->unuse, thread); +} + +/* Free all unused thread. */ +static void +thread_list_free (struct thread_master *m, struct thread_list *list) +{ + struct thread *t; + struct thread *next; + + for (t = list->head; t; t = next) + { + next = t->next; + XFREE (MTYPE_THREAD, t); + list->count--; + m->alloc--; + } +} + +/* Stop thread scheduler. */ +void +thread_master_free (struct thread_master *m) +{ + thread_list_free (m, &m->read); + thread_list_free (m, &m->write); + thread_list_free (m, &m->timer); + thread_list_free (m, &m->event); + thread_list_free (m, &m->ready); + thread_list_free (m, &m->unuse); + + XFREE (MTYPE_THREAD_MASTER, m); +} + +/* Delete top of the list and return it. */ +static struct thread * +thread_trim_head (struct thread_list *list) +{ + if (list->head) + return thread_list_delete (list, list->head); + return NULL; +} + +/* Thread list is empty or not. */ +int +thread_empty (struct thread_list *list) +{ + return list->head ? 0 : 1; +} + +/* Return remain time in second. */ +unsigned long +thread_timer_remain_second (struct thread *thread) +{ + struct timeval timer_now; + + gettimeofday (&timer_now, NULL); + + if (thread->u.sands.tv_sec - timer_now.tv_sec > 0) + return thread->u.sands.tv_sec - timer_now.tv_sec; + else + return 0; +} + +/* Get new thread. */ +static struct thread * +thread_get (struct thread_master *m, u_char type, + int (*func) (struct thread *), void *arg) +{ + struct thread *thread; + + if (m->unuse.head) + thread = thread_trim_head (&m->unuse); + else + { + thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread)); + m->alloc++; + } + thread->type = type; + thread->master = m; + thread->func = func; + thread->arg = arg; + + return thread; +} + +/* Add new read thread. */ +struct thread * +thread_add_read (struct thread_master *m, + int (*func) (struct thread *), void *arg, int fd) +{ + struct thread *thread; + + assert (m != NULL); + + if (FD_ISSET (fd, &m->readfd)) + { + zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd); + return NULL; + } + + thread = thread_get (m, THREAD_READ, func, arg); + FD_SET (fd, &m->readfd); + thread->u.fd = fd; + thread_list_add (&m->read, thread); + + return thread; +} + +/* Add new write thread. */ +struct thread * +thread_add_write (struct thread_master *m, + int (*func) (struct thread *), void *arg, int fd) +{ + struct thread *thread; + + assert (m != NULL); + + if (FD_ISSET (fd, &m->writefd)) + { + zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd); + return NULL; + } + + thread = thread_get (m, THREAD_WRITE, func, arg); + FD_SET (fd, &m->writefd); + thread->u.fd = fd; + thread_list_add (&m->write, thread); + + return thread; +} + +/* Add timer event thread. */ +struct thread * +thread_add_timer (struct thread_master *m, + int (*func) (struct thread *), void *arg, long timer) +{ + struct timeval timer_now; + struct thread *thread; +#ifndef TIMER_NO_SORT + struct thread *tt; +#endif /* TIMER_NO_SORT */ + + assert (m != NULL); + + thread = thread_get (m, THREAD_TIMER, func, arg); + + /* Do we need jitter here? */ + gettimeofday (&timer_now, NULL); + timer_now.tv_sec += timer; + thread->u.sands = timer_now; + + /* Sort by timeval. */ +#ifdef TIMER_NO_SORT + thread_list_add (&m->timer, thread); +#else + for (tt = m->timer.head; tt; tt = tt->next) + if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) + break; + + if (tt) + thread_list_add_before (&m->timer, tt, thread); + else + thread_list_add (&m->timer, thread); +#endif /* TIMER_NO_SORT */ + + return thread; +} + +/* Add timer event thread with "millisecond" resolution */ +struct thread * +thread_add_timer_msec (struct thread_master *m, + int (*func)(struct thread *), + void *arg, long timer) +{ + struct timeval timer_now; + struct thread *thread; +#ifndef TIMER_NO_SORT + struct thread *tt; +#endif /* TIMER_NO_SORT */ + + assert (m != NULL); + + thread = thread_get (m, THREAD_TIMER, func, arg); + + timer = 1000*timer; /* milli -> micro */ + + gettimeofday (&timer_now, NULL); + timer_now.tv_sec += timer / TIMER_SECOND_MICRO; + timer_now.tv_usec += (timer % TIMER_SECOND_MICRO); + thread->u.sands = timer_now; + + + /* Sort by timeval. */ +#ifdef TIMER_NO_SORT + thread_list_add (&m->timer, thread); +#else + for (tt = m->timer.head; tt; tt = tt->next) + if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0) + break; + + if (tt) + thread_list_add_before (&m->timer, tt, thread); + else + thread_list_add (&m->timer, thread); +#endif /* TIMER_NO_SORT */ + + return thread; +} + + +/* Add simple event thread. */ +struct thread * +thread_add_event (struct thread_master *m, + int (*func) (struct thread *), void *arg, int val) +{ + struct thread *thread; + + assert (m != NULL); + + thread = thread_get (m, THREAD_EVENT, func, arg); + thread->u.val = val; + thread_list_add (&m->event, thread); + + return thread; +} + +/* Cancel thread from scheduler. */ +void +thread_cancel (struct thread *thread) +{ + switch (thread->type) + { + case THREAD_READ: + assert (FD_ISSET (thread->u.fd, &thread->master->readfd)); + FD_CLR (thread->u.fd, &thread->master->readfd); + thread_list_delete (&thread->master->read, thread); + break; + case THREAD_WRITE: + assert (FD_ISSET (thread->u.fd, &thread->master->writefd)); + FD_CLR (thread->u.fd, &thread->master->writefd); + thread_list_delete (&thread->master->write, thread); + break; + case THREAD_TIMER: + thread_list_delete (&thread->master->timer, thread); + break; + case THREAD_EVENT: + thread_list_delete (&thread->master->event, thread); + break; + case THREAD_READY: + thread_list_delete (&thread->master->ready, thread); + break; + case THREAD_UNUSED: + thread_list_delete (&thread->master->unuse, thread); + break; + default: + break; + } + thread->type = THREAD_UNUSED; + thread_add_unuse (thread->master, thread); +} + +/* Delete all events which has argument value arg. */ +void +thread_cancel_event (struct thread_master *m, void *arg) +{ + struct thread *thread; + + thread = m->event.head; + while (thread) + { + struct thread *t; + + t = thread; + thread = t->next; + + if (t->arg == arg) + { + thread_list_delete (&m->event, t); + t->type = THREAD_UNUSED; + thread_add_unuse (m, t); + } + } +} + +#ifdef TIMER_NO_SORT +struct timeval * +thread_timer_wait (struct thread_master *m, struct timeval *timer_val) +{ + struct timeval timer_now; + struct timeval timer_min; + struct timeval *timer_wait; + + gettimeofday (&timer_now, NULL); + + timer_wait = NULL; + for (thread = m->timer.head; thread; thread = thread->next) + { + if (! timer_wait) + timer_wait = &thread->u.sands; + else if (timeval_cmp (thread->u.sands, *timer_wait) < 0) + timer_wait = &thread->u.sands; + } + + if (m->timer.head) + { + timer_min = *timer_wait; + timer_min = timeval_subtract (timer_min, timer_now); + if (timer_min.tv_sec < 0) + { + timer_min.tv_sec = 0; + timer_min.tv_usec = 10; + } + timer_wait = &timer_min; + } + else + timer_wait = NULL; + + if (timer_wait) + { + *timer_val = timer_wait; + return timer_val; + } + return NULL; +} +#else /* ! TIMER_NO_SORT */ +struct timeval * +thread_timer_wait (struct thread_master *m, struct timeval *timer_val) +{ + struct timeval timer_now; + struct timeval timer_min; + + if (m->timer.head) + { + gettimeofday (&timer_now, NULL); + timer_min = m->timer.head->u.sands; + timer_min = timeval_subtract (timer_min, timer_now); + if (timer_min.tv_sec < 0) + { + timer_min.tv_sec = 0; + timer_min.tv_usec = 10; + } + *timer_val = timer_min; + return timer_val; + } + return NULL; +} +#endif /* TIMER_NO_SORT */ + +struct thread * +thread_run (struct thread_master *m, struct thread *thread, + struct thread *fetch) +{ + *fetch = *thread; + thread->type = THREAD_UNUSED; + thread_add_unuse (m, thread); + return fetch; +} + +int +thread_process_fd (struct thread_master *m, struct thread_list *list, + fd_set *fdset, fd_set *mfdset) +{ + struct thread *thread; + struct thread *next; + int ready = 0; + + for (thread = list->head; thread; thread = next) + { + next = thread->next; + + if (FD_ISSET (THREAD_FD (thread), fdset)) + { + assert (FD_ISSET (THREAD_FD (thread), mfdset)); + FD_CLR(THREAD_FD (thread), mfdset); + thread_list_delete (list, thread); + thread_list_add (&m->ready, thread); + thread->type = THREAD_READY; + ready++; + } + } + return ready; +} + +/* Fetch next ready thread. */ +struct thread * +thread_fetch (struct thread_master *m, struct thread *fetch) +{ + int num; + int ready; + struct thread *thread; + fd_set readfd; + fd_set writefd; + fd_set exceptfd; + struct timeval timer_now; + struct timeval timer_val; + struct timeval *timer_wait; + struct timeval timer_nowait; + + timer_nowait.tv_sec = 0; + timer_nowait.tv_usec = 0; + + while (1) + { + /* Normal event is the highest priority. */ + if ((thread = thread_trim_head (&m->event)) != NULL) + return thread_run (m, thread, fetch); + + /* Execute timer. */ + gettimeofday (&timer_now, NULL); + + for (thread = m->timer.head; thread; thread = thread->next) + if (timeval_cmp (timer_now, thread->u.sands) >= 0) + { + thread_list_delete (&m->timer, thread); + return thread_run (m, thread, fetch); + } + + /* If there are any ready threads, process top of them. */ + if ((thread = thread_trim_head (&m->ready)) != NULL) + return thread_run (m, thread, fetch); + + /* Structure copy. */ + readfd = m->readfd; + writefd = m->writefd; + exceptfd = m->exceptfd; + + /* Calculate select wait timer. */ + timer_wait = thread_timer_wait (m, &timer_val); + + num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); + + if (num == 0) + continue; + + if (num < 0) + { + if (errno == EINTR) + continue; + + zlog_warn ("select() error: %s", strerror (errno)); + return NULL; + } + + /* Normal priority read thead. */ + ready = thread_process_fd (m, &m->read, &readfd, &m->readfd); + + /* Write thead. */ + ready = thread_process_fd (m, &m->write, &writefd, &m->writefd); + + if ((thread = thread_trim_head (&m->ready)) != NULL) + return thread_run (m, thread, fetch); + } +} + +static unsigned long +thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start) +{ + unsigned long thread_time; + +#ifdef HAVE_RUSAGE + /* This is 'user + sys' time. */ + thread_time = timeval_elapsed (now->ru_utime, start->ru_utime); + thread_time += timeval_elapsed (now->ru_stime, start->ru_stime); +#else + /* When rusage is not available, simple elapsed time is used. */ + thread_time = timeval_elapsed (*now, *start); +#endif /* HAVE_RUSAGE */ + + return thread_time; +} + +/* We should aim to yield after THREAD_YIELD_TIME_SLOT + milliseconds. */ +int +thread_should_yield (struct thread *thread) +{ + RUSAGE_T ru; + + GETRUSAGE (&ru); + + if (thread_consumed_time (&ru, &thread->ru) > THREAD_YIELD_TIME_SLOT) + return 1; + else + return 0; +} + +/* We check thread consumed time. If the system has getrusage, we'll + use that to get indepth stats on the performance of the thread. If + not - we'll use gettimeofday for some guestimation. */ +void +thread_call (struct thread *thread) +{ + unsigned long thread_time; + RUSAGE_T ru; + + GETRUSAGE (&thread->ru); + + (*thread->func) (thread); + + GETRUSAGE (&ru); + + thread_time = thread_consumed_time (&ru, &thread->ru); + +#ifdef THREAD_CONSUMED_TIME_CHECK + if (thread_time > 200000L) + { + /* + * We have a CPU Hog on our hands. + * Whinge about it now, so we're aware this is yet another task + * to fix. + */ + zlog_err ("CPU HOG task %lx ran for %ldms", + /* FIXME: report the name of the function somehow */ + (unsigned long) thread->func, + thread_time / 1000L); + } +#endif /* THREAD_CONSUMED_TIME_CHECK */ +} + +/* Execute thread */ +struct thread * +thread_execute (struct thread_master *m, + int (*func)(struct thread *), + void *arg, + int val) +{ + struct thread dummy; + + memset (&dummy, 0, sizeof (struct thread)); + + dummy.type = THREAD_EVENT; + dummy.master = NULL; + dummy.func = func; + dummy.arg = arg; + dummy.u.val = val; + thread_call (&dummy); + + return NULL; +} diff --git a/isisd/modified/thread.h b/isisd/modified/thread.h new file mode 100644 index 00000000..c3fac435 --- /dev/null +++ b/isisd/modified/thread.h @@ -0,0 +1,141 @@ +/* Thread management routine header. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_THREAD_H +#define _ZEBRA_THREAD_H + +#ifdef HAVE_RUSAGE +#define RUSAGE_T struct rusage +#define GETRUSAGE(X) getrusage (RUSAGE_SELF, X); +#else +#define RUSAGE_T struct timeval +#define GETRUSAGE(X) gettimeofday (X, NULL); +#endif /* HAVE_RUSAGE */ + +/* Linked list of thread. */ +struct thread_list +{ + struct thread *head; + struct thread *tail; + int count; +}; + +/* Master of the theads. */ +struct thread_master +{ + struct thread_list read; + struct thread_list write; + struct thread_list timer; + struct thread_list event; + struct thread_list ready; + struct thread_list unuse; + fd_set readfd; + fd_set writefd; + fd_set exceptfd; + unsigned long alloc; +}; + +/* Thread itself. */ +struct thread +{ + unsigned char type; /* thread type */ + struct thread *next; /* next pointer of the thread */ + struct thread *prev; /* previous pointer of the thread */ + struct thread_master *master; /* pointer to the struct thread_master. */ + int (*func) (struct thread *); /* event function */ + void *arg; /* event argument */ + union { + int val; /* second argument of the event. */ + int fd; /* file descriptor in case of read/write. */ + struct timeval sands; /* rest of time sands value. */ + } u; + RUSAGE_T ru; /* Indepth usage info. */ +}; + +/* Thread types. */ +#define THREAD_READ 0 +#define THREAD_WRITE 1 +#define THREAD_TIMER 2 +#define THREAD_EVENT 3 +#define THREAD_READY 4 +#define THREAD_UNUSED 5 + +/* Thread yield time. */ +#define THREAD_YIELD_TIME_SLOT 100 * 1000L /* 100ms */ + +/* Macros. */ +#define THREAD_ARG(X) ((X)->arg) +#define THREAD_FD(X) ((X)->u.fd) +#define THREAD_VAL(X) ((X)->u.val) + +#define THREAD_READ_ON(master,thread,func,arg,sock) \ + do { \ + if (! thread) \ + thread = thread_add_read (master, func, arg, sock); \ + } while (0) + +#define THREAD_WRITE_ON(master,thread,func,arg,sock) \ + do { \ + if (! thread) \ + thread = thread_add_write (master, func, arg, sock); \ + } while (0) + +#define THREAD_TIMER_ON(master,thread,func,arg,time) \ + do { \ + if (! thread) \ + thread = thread_add_timer (master, func, arg, time); \ + } while (0) + +#define THREAD_OFF(thread) \ + do { \ + if (thread) \ + { \ + thread_cancel (thread); \ + thread = NULL; \ + } \ + } while (0) + +#define THREAD_READ_OFF(thread) THREAD_OFF(thread) +#define THREAD_WRITE_OFF(thread) THREAD_OFF(thread) +#define THREAD_TIMER_OFF(thread) THREAD_OFF(thread) + +/* Prototypes. */ +struct thread_master *thread_master_create (); +struct thread *thread_add_read (struct thread_master *, + int (*)(struct thread *), void *, int); +struct thread *thread_add_write (struct thread_master *, + int (*)(struct thread *), void *, int); +struct thread *thread_add_timer (struct thread_master *, + int (*)(struct thread *), void *, long); +struct thread *thread_add_timer_msec (struct thread_master *, + int (*)(struct thread *), void *, long); +struct thread *thread_add_event (struct thread_master *, + int (*)(struct thread *), void *, int ); +void thread_cancel (struct thread *); +void thread_cancel_event (struct thread_master *, void *); + +struct thread *thread_fetch (struct thread_master *, struct thread *); +struct thread *thread_execute (struct thread_master *, + int (*)(struct thread *), void *, int); +void thread_call (struct thread *); +unsigned long thread_timer_remain_second (struct thread *); + +#endif /* _ZEBRA_THREAD_H */ diff --git a/isisd/modified/vty.c b/isisd/modified/vty.c new file mode 100644 index 00000000..6de0e0da --- /dev/null +++ b/isisd/modified/vty.c @@ -0,0 +1,2786 @@ +/* + * 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 <zebra.h> + +#include "linklist.h" +#include "buffer.h" +#include "version.h" +#include "command.h" +#include "sockunion.h" +#include "thread.h" +#include "memory.h" +#include "str.h" +#include "log.h" +#include "prefix.h" +#include "filter.h" + +/* Vty events */ +enum event +{ + VTY_SERV, + VTY_READ, + VTY_WRITE, + VTY_TIMEOUT_RESET, +#ifdef VTYSH + VTYSH_SERV, + VTYSH_READ +#endif /* VTYSH */ +}; + +static void vty_event (enum event, int, struct vty *); + +/* Extern host structure from command.c */ +extern struct host host; + +/* Vector which store each vty structure. */ +static vector vtyvec; + +/* Vty timeout value. */ +static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT; + +/* Vty access-class command */ +static char *vty_accesslist_name = NULL; + +/* Vty access-calss for IPv6. */ +static char *vty_ipv6_accesslist_name = NULL; + +/* VTY server thread. */ +vector Vvty_serv_thread; + +/* Current directory. */ +char *vty_cwd = NULL; + +/* Configure lock. */ +static int vty_config; + +/* Login password check. */ +static int no_password_check = 0; + +/* Integrated configuration file path */ +char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG; + + +/* VTY standard output function. */ +int +vty_out (struct vty *vty, const char *format, ...) +{ + va_list args; + int len = 0; + int size = 1024; + char buf[1024]; + char *p = NULL; + + va_start (args, format); + + if (vty_shell (vty)) + vprintf (format, args); + else + { + /* Try to write to initial buffer. */ + len = vsnprintf (buf, sizeof buf, format, args); + + /* Initial buffer is not enough. */ + if (len < 0 || len >= size) + { + while (1) + { + if (len > -1) + size = len + 1; + else + size = size * 2; + + p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size); + if (! p) + return -1; + + len = vsnprintf (p, size, format, args); + + if (len > -1 && len < size) + break; + } + } + + /* When initial buffer is enough to store all output. */ + if (! p) + p = buf; + + /* Pointer p must point out buffer. */ + if (vty_shell_serv (vty)) + write (vty->fd, (u_char *) p, len); + else + buffer_write (vty->obuf, (u_char *) p, len); + + /* If p is not different with buf, it is allocated buffer. */ + if (p != buf) + XFREE (MTYPE_VTY_OUT_BUF, p); + } + + va_end (args); + + return len; +} + +int +vty_log_out (struct vty *vty, const char *proto_str, const char *format, + va_list va) +{ + int len; + char buf[1024]; + + snprintf (buf, sizeof buf, "%s: ", proto_str); + write (vty->fd, buf, strlen (proto_str) + 2); + + len = vsnprintf (buf, sizeof buf, format, va); + if (len < 0) + return -1; + write (vty->fd, (u_char *)buf, len); + + snprintf (buf, sizeof buf, "\r\n"); + write (vty->fd, buf, 2); + + return len; +} + +/* Output current time to the vty. */ +void +vty_time_print (struct vty *vty, int cr) +{ + time_t clock; + struct tm *tm; +#define TIME_BUF 25 + char buf [TIME_BUF]; + int ret; + + time (&clock); + tm = localtime (&clock); + + ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); + if (ret == 0) + { + zlog (NULL, LOG_INFO, "strftime error"); + return; + } + if (cr) + vty_out (vty, "%s\n", buf); + else + vty_out (vty, "%s ", buf); + + return; +} + +/* Say hello to vty interface. */ +void +vty_hello (struct vty *vty) +{ + if (host.motd) + vty_out (vty, host.motd); +} + +/* Put out prompt and wait input from user. */ +static void +vty_prompt (struct vty *vty) +{ + struct utsname names; + const char*hostname; + + if (vty->type == VTY_TERM) + { + hostname = host.name; + if (!hostname) + { + uname (&names); + hostname = names.nodename; + } + vty_out (vty, cmd_prompt (vty->node), hostname); + } +} + +/* Send WILL TELOPT_ECHO to remote server. */ +void +vty_will_echo (struct vty *vty) +{ + char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Make suppress Go-Ahead telnet option. */ +static void +vty_will_suppress_go_ahead (struct vty *vty) +{ + char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Make don't use linemode over telnet. */ +static void +vty_dont_linemode (struct vty *vty) +{ + char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; + vty_out (vty, "%s", cmd); +} + +/* Use window size. */ +static void +vty_do_window_size (struct vty *vty) +{ + char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' }; + vty_out (vty, "%s", cmd); +} + +#if 0 /* Currently not used. */ +/* Make don't use lflow vty interface. */ +static void +vty_dont_lflow_ahead (struct vty *vty) +{ + char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' }; + vty_out (vty, "%s", cmd); +} +#endif /* 0 */ + +/* Allocate new vty struct. */ +struct vty * +vty_new () +{ + struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty)); + + new->obuf = (struct buffer *) buffer_new (100); + new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); + new->max = VTY_BUFSIZ; + new->sb_buffer = NULL; + + return new; +} + +/* Authentication of vty */ +static void +vty_auth (struct vty *vty, char *buf) +{ + char *passwd = NULL; + enum node_type next_node = 0; + int fail; + char *crypt (const char *, const char *); + + switch (vty->node) + { + case AUTH_NODE: + if (host.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 = VIEW_NODE; + } + } + } +} + +/* Command execution over the vty interface. */ +int +vty_command (struct vty *vty, char *buf) +{ + int ret; + vector vline; + + /* Split readline string up into the vector */ + vline = cmd_make_strvec (buf); + + if (vline == NULL) + return CMD_SUCCESS; + + ret = cmd_execute_command (vline, vty, NULL); + + if (ret != CMD_SUCCESS) + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + vty_out (vty, "Warning...%s", VTY_NEWLINE); + break; + case CMD_ERR_AMBIGUOUS: + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + break; + case CMD_ERR_NO_MATCH: + vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE); + break; + case CMD_ERR_INCOMPLETE: + vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE); + break; + } + cmd_free_strvec (vline); + + return ret; +} + +char telnet_backward_char = 0x08; +char telnet_space_char = ' '; + +/* Basic function to write buffer to vty. */ +static void +vty_write (struct vty *vty, char *buf, size_t nbytes) +{ + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + /* Should we do buffering here ? And make vty_flush (vty) ? */ + buffer_write (vty->obuf, (u_char *)buf, nbytes); +} + +/* Ensure length of input buffer. Is buffer is short, double it. */ +static void +vty_ensure (struct vty *vty, int length) +{ + if (vty->max <= length) + { + vty->max *= 2; + vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max); + } +} + +/* Basic function to insert character into vty. */ +static void +vty_self_insert (struct vty *vty, char c) +{ + int i; + int length; + + vty_ensure (vty, vty->length + 1); + length = vty->length - vty->cp; + memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length); + vty->buf[vty->cp] = c; + + vty_write (vty, &vty->buf[vty->cp], length + 1); + for (i = 0; i < length; i++) + vty_write (vty, &telnet_backward_char, 1); + + vty->cp++; + vty->length++; +} + +/* Self insert character 'c' in overwrite mode. */ +static void +vty_self_insert_overwrite (struct vty *vty, char c) +{ + vty_ensure (vty, vty->length + 1); + vty->buf[vty->cp++] = c; + + if (vty->cp > vty->length) + vty->length++; + + if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE)) + return; + + vty_write (vty, &c, 1); +} + +/* Insert a word into vty interface with overwrite mode. */ +static void +vty_insert_word_overwrite (struct vty *vty, char *str) +{ + int len = strlen (str); + vty_write (vty, str, len); + strcpy (&vty->buf[vty->cp], str); + vty->cp += len; + vty->length = vty->cp; +} + +/* Forward character. */ +static void +vty_forward_char (struct vty *vty) +{ + if (vty->cp < vty->length) + { + vty_write (vty, &vty->buf[vty->cp], 1); + vty->cp++; + } +} + +/* Backward character. */ +static void +vty_backward_char (struct vty *vty) +{ + if (vty->cp > 0) + { + vty->cp--; + vty_write (vty, &telnet_backward_char, 1); + } +} + +/* Move to the beginning of the line. */ +static void +vty_beginning_of_line (struct vty *vty) +{ + while (vty->cp) + vty_backward_char (vty); +} + +/* Move to the end of the line. */ +static void +vty_end_of_line (struct vty *vty) +{ + while (vty->cp < vty->length) + vty_forward_char (vty); +} + +static void vty_kill_line_from_beginning (struct vty *); +static void vty_redraw_line (struct vty *); + +/* Print command line history. This function is called from + vty_next_line and vty_previous_line. */ +static void +vty_history_print (struct vty *vty) +{ + int length; + + vty_kill_line_from_beginning (vty); + + /* Get previous line from history buffer */ + length = strlen (vty->hist[vty->hp]); + memcpy (vty->buf, vty->hist[vty->hp], length); + vty->cp = vty->length = length; + + /* Redraw current line */ + vty_redraw_line (vty); +} + +/* Show next command line history. */ +void +vty_next_line (struct vty *vty) +{ + int try_index; + + if (vty->hp == vty->hindex) + return; + + /* Try is there history exist or not. */ + try_index = vty->hp; + if (try_index == (VTY_MAXHIST - 1)) + try_index = 0; + else + try_index++; + + /* If there is not history return. */ + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print (vty); +} + +/* Show previous command line history. */ +void +vty_previous_line (struct vty *vty) +{ + int try_index; + + try_index = vty->hp; + if (try_index == 0) + try_index = VTY_MAXHIST - 1; + else + try_index--; + + if (vty->hist[try_index] == NULL) + return; + else + vty->hp = try_index; + + vty_history_print (vty); +} + +/* This function redraw all of the command line character. */ +static void +vty_redraw_line (struct vty *vty) +{ + vty_write (vty, vty->buf, vty->length); + vty->cp = vty->length; +} + +/* Forward word. */ +static void +vty_forward_word (struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_forward_char (vty); + + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_forward_char (vty); +} + +/* Backward word without skipping training space. */ +static void +vty_backward_pure_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char (vty); +} + +/* Backward word. */ +static void +vty_backward_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_backward_char (vty); + + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_backward_char (vty); +} + +/* When '^D' is typed at the beginning of the line we move to the down + level. */ +static void +vty_down_level (struct vty *vty) +{ + vty_out (vty, "%s", VTY_NEWLINE); + config_exit (NULL, vty, 0, NULL); + vty_prompt (vty); + vty->cp = 0; +} + +/* When '^Z' is received from vty, move down to the enable mode. */ +void +vty_end_config (struct vty *vty) +{ + vty_out (vty, "%s", VTY_NEWLINE); + + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case BGP_VPNV4_NODE: + case BGP_IPV4_NODE: + case BGP_IPV4M_NODE: + case BGP_IPV6_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case 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->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + if (vty->length == 0) + { + vty_down_level (vty); + return; + } + + if (vty->cp == vty->length) + return; /* completion need here? */ + + size = vty->length - vty->cp; + + vty->length--; + memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1); + vty->buf[vty->length] = '\0'; + + vty_write (vty, &vty->buf[vty->cp], size - 1); + vty_write (vty, &telnet_space_char, 1); + + for (i = 0; i < size; i++) + vty_write (vty, &telnet_backward_char, 1); +} + +/* Delete a character before the point. */ +static void +vty_delete_backward_char (struct vty *vty) +{ + if (vty->cp == 0) + return; + + vty_backward_char (vty); + vty_delete_char (vty); +} + +/* Kill rest of line from current point. */ +static void +vty_kill_line (struct vty *vty) +{ + int i; + int size; + + size = vty->length - vty->cp; + + if (size == 0) + return; + + for (i = 0; i < size; i++) + vty_write (vty, &telnet_space_char, 1); + for (i = 0; i < size; i++) + vty_write (vty, &telnet_backward_char, 1); + + memset (&vty->buf[vty->cp], 0, size); + vty->length = vty->cp; +} + +/* Kill line from the beginning. */ +static void +vty_kill_line_from_beginning (struct vty *vty) +{ + vty_beginning_of_line (vty); + vty_kill_line (vty); +} + +/* Delete a word before the point. */ +static void +vty_forward_kill_word (struct vty *vty) +{ + while (vty->cp != vty->length && vty->buf[vty->cp] == ' ') + vty_delete_char (vty); + while (vty->cp != vty->length && vty->buf[vty->cp] != ' ') + vty_delete_char (vty); +} + +/* Delete a word before the point. */ +static void +vty_backward_kill_word (struct vty *vty) +{ + while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ') + vty_delete_backward_char (vty); + while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ') + vty_delete_backward_char (vty); +} + +/* Transpose chars before or at the point. */ +static void +vty_transpose_chars (struct vty *vty) +{ + char c1, c2; + + /* If length is short or point is near by the beginning of line then + return. */ + if (vty->length < 2 || vty->cp < 1) + return; + + /* In case of point is located at the end of the line. */ + if (vty->cp == vty->length) + { + c1 = vty->buf[vty->cp - 1]; + c2 = vty->buf[vty->cp - 2]; + + vty_backward_char (vty); + vty_backward_char (vty); + vty_self_insert_overwrite (vty, c1); + vty_self_insert_overwrite (vty, c2); + } + else + { + c1 = vty->buf[vty->cp]; + c2 = vty->buf[vty->cp - 1]; + + vty_backward_char (vty); + vty_self_insert_overwrite (vty, c1); + vty_self_insert_overwrite (vty, c2); + } +} + +/* Do completion at vty interface. */ +static void +vty_complete_command (struct vty *vty) +{ + int i; + int ret; + char **matched = NULL; + vector vline; + + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + return; + + vline = cmd_make_strvec (vty->buf); + if (vline == NULL) + return; + + /* In case of 'help \t'. */ + if (isspace ((int) vty->buf[vty->length - 1])) + vector_set (vline, '\0'); + + matched = cmd_complete_command (vline, vty, &ret); + + cmd_free_strvec (vline); + + vty_out (vty, "%s", VTY_NEWLINE); + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_ERR_NO_MATCH: + /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */ + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_COMPLETE_FULL_MATCH: + vty_prompt (vty); + vty_redraw_line (vty); + vty_backward_pure_word (vty); + vty_insert_word_overwrite (vty, matched[0]); + vty_self_insert (vty, ' '); + XFREE (MTYPE_TMP, matched[0]); + break; + case CMD_COMPLETE_MATCH: + vty_prompt (vty); + vty_redraw_line (vty); + vty_backward_pure_word (vty); + vty_insert_word_overwrite (vty, matched[0]); + XFREE (MTYPE_TMP, matched[0]); + vector_only_index_free (matched); + return; + break; + case CMD_COMPLETE_LIST_MATCH: + for (i = 0; matched[i] != NULL; i++) + { + if (i != 0 && ((i % 6) == 0)) + vty_out (vty, "%s", VTY_NEWLINE); + vty_out (vty, "%-10s ", matched[i]); + XFREE (MTYPE_TMP, matched[i]); + } + vty_out (vty, "%s", VTY_NEWLINE); + + vty_prompt (vty); + vty_redraw_line (vty); + break; + case CMD_ERR_NOTHING_TODO: + vty_prompt (vty); + vty_redraw_line (vty); + break; + default: + break; + } + if (matched) + vector_only_index_free (matched); +} + +void +vty_describe_fold (struct vty *vty, int cmd_width, + int desc_width, struct desc *desc) +{ + char *buf, *cmd, *p; + int pos; + + cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd; + + if (desc_width <= 0) + { + vty_out (vty, " %-*s %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE); + return; + } + + buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1); + + for (p = desc->str; strlen (p) > desc_width; p += pos + 1) + { + for (pos = desc_width; pos > 0; pos--) + if (*(p + pos) == ' ') + break; + + if (pos == 0) + break; + + strncpy (buf, p, pos); + buf[pos] = '\0'; + vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE); + + cmd = ""; + } + + vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE); + + XFREE (MTYPE_TMP, buf); +} + +/* Describe matched command function. */ +static void +vty_describe_command (struct vty *vty) +{ + int ret; + vector vline; + vector describe; + int i, width, desc_width; + struct desc *desc, *desc_cr = NULL; + + vline = cmd_make_strvec (vty->buf); + + /* In case of '> ?'. */ + if (vline == NULL) + { + vline = vector_init (1); + vector_set (vline, '\0'); + } + else + if (isspace ((int) vty->buf[vty->length - 1])) + vector_set (vline, '\0'); + + describe = cmd_describe_command (vline, vty, &ret); + + vty_out (vty, "%s", VTY_NEWLINE); + + /* Ambiguous error. */ + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + cmd_free_strvec (vline); + vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + return; + break; + case CMD_ERR_NO_MATCH: + cmd_free_strvec (vline); + vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); + vty_prompt (vty); + vty_redraw_line (vty); + return; + break; + } + + /* Get width of command string. */ + width = 0; + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + int len; + + if (desc->cmd[0] == '\0') + continue; + + len = strlen (desc->cmd); + if (desc->cmd[0] == '.') + len--; + + if (width < len) + width = len; + } + + /* Get width of description string. */ + desc_width = vty->width - (width + 6); + + /* Print out description. */ + for (i = 0; i < vector_max (describe); i++) + if ((desc = vector_slot (describe, i)) != NULL) + { + if (desc->cmd[0] == '\0') + continue; + + if (strcmp (desc->cmd, "<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); + } + + cmd_free_strvec (vline); + vector_free (describe); + + vty_prompt (vty); + vty_redraw_line (vty); +} + +void +vty_clear_buf (struct vty *vty) +{ + memset (vty->buf, 0, vty->max); +} + +/* ^C stop current input and do not add command line to the history. */ +static void +vty_stop_input (struct vty *vty) +{ + vty->cp = vty->length = 0; + vty_clear_buf (vty); + vty_out (vty, "%s", VTY_NEWLINE); + + switch (vty->node) + { + case VIEW_NODE: + case ENABLE_NODE: + /* Nothing to do. */ + break; + case CONFIG_NODE: + case INTERFACE_NODE: + case ZEBRA_NODE: + case RIP_NODE: + case RIPNG_NODE: + case BGP_NODE: + case RMAP_NODE: + case OSPF_NODE: + case OSPF6_NODE: + case 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: + buffer_reset(vty->sb_buffer); + vty->iac_sb_in_progress = 1; + return 0; + break; + case SE: + { + char *buffer = (char *)vty->sb_buffer->head->data; + int length = vty->sb_buffer->length; + + if (buffer == NULL) + return 0; + + if (!vty->iac_sb_in_progress) + return 0; + + if (buffer[0] == '\0') + { + vty->iac_sb_in_progress = 0; + return 0; + } + switch (buffer[0]) + { + case TELOPT_NAWS: + if (length < 5) + break; + vty->width = buffer[2]; + vty->height = vty->lines >= 0 ? vty->lines : buffer[4]; + break; + } + vty->iac_sb_in_progress = 0; + return 0; + break; + } + default: + break; + } + return 1; +} + +/* Execute current command line. */ +static int +vty_execute (struct vty *vty) +{ + int ret; + + ret = CMD_SUCCESS; + + switch (vty->node) + { + case AUTH_NODE: + case AUTH_ENABLE_NODE: + vty_auth (vty, vty->buf); + break; + default: + ret = vty_command (vty, vty->buf); + if (vty->type == VTY_TERM) + vty_hist_add (vty); + break; + } + + /* Clear command line buffer. */ + vty->cp = vty->length = 0; + vty_clear_buf (vty); + + if (vty->status != VTY_CLOSE + && vty->status != VTY_START + && vty->status != VTY_CONTINUE) + vty_prompt (vty); + + return ret; +} + +#define CONTROL(X) ((X) - '@') +#define VTY_NORMAL 0 +#define VTY_PRE_ESCAPE 1 +#define VTY_ESCAPE 2 + +/* Escape character command map. */ +static void +vty_escape_map (unsigned char c, struct vty *vty) +{ + switch (c) + { + case ('A'): + vty_previous_line (vty); + break; + case ('B'): + vty_next_line (vty); + break; + case ('C'): + vty_forward_char (vty); + break; + case ('D'): + vty_backward_char (vty); + break; + default: + break; + } + + /* Go back to normal mode. */ + vty->escape = VTY_NORMAL; +} + +/* Quit print out to the buffer. */ +static void +vty_buffer_reset (struct vty *vty) +{ + buffer_reset (vty->obuf); + vty_prompt (vty); + vty_redraw_line (vty); +} + +/* Read data via vty socket. */ +static int +vty_read (struct thread *thread) +{ + int i; + int ret; + int nbytes; + unsigned char buf[VTY_READ_BUFSIZ]; + + int vty_sock = THREAD_FD (thread); + struct vty *vty = THREAD_ARG (thread); + vty->t_read = NULL; + + /* Read raw data from socket */ + nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ); + if (nbytes <= 0) + vty->status = VTY_CLOSE; + + for (i = 0; i < nbytes; i++) + { + if (buf[i] == IAC) + { + if (!vty->iac) + { + vty->iac = 1; + continue; + } + else + { + vty->iac = 0; + } + } + + if (vty->iac_sb_in_progress && !vty->iac) + { + buffer_putc(vty->sb_buffer, buf[i]); + continue; + } + + if (vty->iac) + { + /* In case of telnet command */ + ret = vty_telnet_option (vty, buf + i, nbytes - i); + vty->iac = 0; + i += ret; + continue; + } + + if (vty->status == VTY_MORE) + { + switch (buf[i]) + { + case CONTROL('C'): + case 'q': + case 'Q': + if (vty->output_func) + (*vty->output_func) (vty, 1); + vty_buffer_reset (vty); + break; + default: + if (vty->output_func) + (*vty->output_func) (vty, 0); + break; + } + continue; + } + + /* Escape character. */ + if (vty->escape == VTY_ESCAPE) + { + vty_escape_map (buf[i], vty); + continue; + } + + /* Pre-escape status. */ + if (vty->escape == VTY_PRE_ESCAPE) + { + switch (buf[i]) + { + case '[': + vty->escape = VTY_ESCAPE; + break; + case 'b': + vty_backward_word (vty); + vty->escape = VTY_NORMAL; + break; + case 'f': + vty_forward_word (vty); + vty->escape = VTY_NORMAL; + break; + case 'd': + vty_forward_kill_word (vty); + vty->escape = VTY_NORMAL; + break; + case CONTROL('H'): + case 0x7f: + vty_backward_kill_word (vty); + vty->escape = VTY_NORMAL; + break; + default: + vty->escape = VTY_NORMAL; + break; + } + continue; + } + + switch (buf[i]) + { + case CONTROL('A'): + vty_beginning_of_line (vty); + break; + case CONTROL('B'): + vty_backward_char (vty); + break; + case CONTROL('C'): + vty_stop_input (vty); + break; + case CONTROL('D'): + vty_delete_char (vty); + break; + case CONTROL('E'): + vty_end_of_line (vty); + break; + case CONTROL('F'): + vty_forward_char (vty); + break; + case CONTROL('H'): + case 0x7f: + vty_delete_backward_char (vty); + break; + case CONTROL('K'): + vty_kill_line (vty); + break; + case CONTROL('N'): + vty_next_line (vty); + break; + case CONTROL('P'): + vty_previous_line (vty); + break; + case CONTROL('T'): + vty_transpose_chars (vty); + break; + case CONTROL('U'): + vty_kill_line_from_beginning (vty); + break; + case CONTROL('W'): + vty_backward_kill_word (vty); + break; + case CONTROL('Z'): + vty_end_config (vty); + break; + case '\n': + case '\r': + vty_out (vty, "%s", VTY_NEWLINE); + vty_execute (vty); + break; + case '\t': + vty_complete_command (vty); + break; + case '?': + if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE) + vty_self_insert (vty, buf[i]); + else + vty_describe_command (vty); + break; + case '\033': + if (i + 1 < nbytes && buf[i + 1] == '[') + { + vty->escape = VTY_ESCAPE; + i++; + } + else + vty->escape = VTY_PRE_ESCAPE; + break; + default: + if (buf[i] > 31 && buf[i] < 127) + vty_self_insert (vty, buf[i]); + break; + } + } + + /* Check status. */ + if (vty->status == VTY_CLOSE) + vty_close (vty); + else + { + vty_event (VTY_WRITE, vty_sock, vty); + vty_event (VTY_READ, vty_sock, vty); + } + return 0; +} + +/* Flush buffer to the vty. */ +static int +vty_flush (struct thread *thread) +{ + int erase; + int dont_more; + int vty_sock = THREAD_FD (thread); + struct vty *vty = THREAD_ARG (thread); + vty->t_write = NULL; + + /* Tempolary disable read thread. */ + if (vty->lines == 0) + if (vty->t_read) + { + thread_cancel (vty->t_read); + vty->t_read = NULL; + } + + /* Function execution continue. */ + if (vty->status == VTY_START || vty->status == VTY_CONTINUE) + { + if (vty->status == VTY_CONTINUE) + erase = 1; + else + erase = 0; + + if (vty->output_func == NULL) + dont_more = 1; + else + dont_more = 0; + + if (vty->lines == 0) + { + erase = 0; + dont_more = 1; + } + + buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more); + + if (vty->status == VTY_CLOSE) + { + vty_close (vty); + return 0; + } + + if (vty->output_func == NULL) + { + vty->status = VTY_NORMAL; + vty_prompt (vty); + vty_event (VTY_WRITE, vty_sock, vty); + } + else + vty->status = VTY_MORE; + + if (vty->lines == 0) + { + if (vty->output_func == NULL) + vty_event (VTY_READ, vty_sock, vty); + else + { + if (vty->output_func) + (*vty->output_func) (vty, 0); + vty_event (VTY_WRITE, vty_sock, vty); + } + } + } + else + { + if (vty->status == VTY_MORE) + erase = 1; + else + erase = 0; + + if (vty->lines == 0) + buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1); + else + buffer_flush_window (vty->obuf, vty->fd, vty->width, + vty->lines >= 0 ? vty->lines : vty->height, + erase, 0); + + if (buffer_empty (vty->obuf)) + { + if (vty->status == VTY_CLOSE) + vty_close (vty); + else + { + vty->status = VTY_NORMAL; + + if (vty->lines == 0) + vty_event (VTY_READ, vty_sock, vty); + } + } + else + { + vty->status = VTY_MORE; + + if (vty->lines == 0) + vty_event (VTY_WRITE, vty_sock, vty); + } + } + + return 0; +} + +/* Create new vty structure. */ +struct vty * +vty_create (int vty_sock, union sockunion *su) +{ + struct vty *vty; + + /* Allocate new vty structure and set up default values. */ + vty = vty_new (); + vty->fd = vty_sock; + vty->type = VTY_TERM; + vty->address = sockunion_su2str (su); + if (no_password_check) + { + if (host.advanced) + vty->node = ENABLE_NODE; + else + vty->node = VIEW_NODE; + } + else + vty->node = AUTH_NODE; + vty->fail = 0; + vty->cp = 0; + vty_clear_buf (vty); + vty->length = 0; + memset (vty->hist, 0, sizeof (vty->hist)); + vty->hp = 0; + vty->hindex = 0; + vector_set_index (vtyvec, vty_sock, vty); + vty->status = VTY_NORMAL; + vty->v_timeout = vty_timeout_val; + if (host.lines >= 0) + vty->lines = host.lines; + else + vty->lines = -1; + vty->iac = 0; + vty->iac_sb_in_progress = 0; + vty->sb_buffer = buffer_new (1024); + + if (! no_password_check) + { + /* Vty is not available if password isn't set. */ + if (host.password == NULL && host.password_encrypt == NULL) + { + vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE); + vty->status = VTY_CLOSE; + vty_close (vty); + return NULL; + } + } + + /* Say hello to the world. */ + vty_hello (vty); + if (! no_password_check) + vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + + /* Setting up terminal. */ + vty_will_echo (vty); + vty_will_suppress_go_ahead (vty); + + vty_dont_linemode (vty); + vty_do_window_size (vty); + /* vty_dont_lflow_ahead (vty); */ + + vty_prompt (vty); + + /* Add read/write thread. */ + vty_event (VTY_WRITE, vty_sock, vty); + vty_event (VTY_READ, vty_sock, vty); + + return vty; +} + +/* Accept connection from the network. */ +static int +vty_accept (struct thread *thread) +{ + int vty_sock; + struct vty *vty; + union sockunion su; + int ret; + unsigned int on; + int accept_sock; + struct prefix *p = NULL; + struct access_list *acl = NULL; + + accept_sock = THREAD_FD (thread); + + /* We continue hearing vty socket. */ + vty_event (VTY_SERV, accept_sock, NULL); + + memset (&su, 0, sizeof (union sockunion)); + + /* We can handle IPv4 or IPv6 socket. */ + vty_sock = sockunion_accept (accept_sock, &su); + if (vty_sock < 0) + { + zlog_warn ("can't accept vty socket : %s", strerror (errno)); + return -1; + } + + p = sockunion2hostprefix (&su); + + /* VTY's accesslist apply. */ + if (p->family == AF_INET && vty_accesslist_name) + { + if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) && + (access_list_apply (acl, p) == FILTER_DENY)) + { + char *buf; + zlog (NULL, LOG_INFO, "Vty connection refused from %s", + (buf = sockunion_su2str (&su))); + free (buf); + close (vty_sock); + + /* continue accepting connections */ + vty_event (VTY_SERV, accept_sock, NULL); + + prefix_free (p); + + return 0; + } + } + +#ifdef HAVE_IPV6 + /* VTY's ipv6 accesslist apply. */ + if (p->family == AF_INET6 && vty_ipv6_accesslist_name) + { + if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) && + (access_list_apply (acl, p) == FILTER_DENY)) + { + char *buf; + zlog (NULL, LOG_INFO, "Vty connection refused from %s", + (buf = sockunion_su2str (&su))); + free (buf); + close (vty_sock); + + /* continue accepting connections */ + vty_event (VTY_SERV, accept_sock, NULL); + + prefix_free (p); + + return 0; + } + } +#endif /* HAVE_IPV6 */ + + prefix_free (p); + + on = 1; + ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &on, sizeof (on)); + if (ret < 0) + zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", + strerror (errno)); + + vty = vty_create (vty_sock, &su); + + return 0; +} + +#if defined(HAVE_IPV6) && !defined(NRL) +void +vty_serv_sock_addrinfo (const char *hostname, unsigned short port) +{ + int ret; + struct addrinfo req; + struct addrinfo *ainfo; + struct addrinfo *ainfo_save; + int sock; + char port_str[BUFSIZ]; + + memset (&req, 0, sizeof (struct addrinfo)); + req.ai_flags = AI_PASSIVE; + req.ai_family = AF_UNSPEC; + req.ai_socktype = SOCK_STREAM; + sprintf (port_str, "%d", port); + port_str[sizeof (port_str) - 1] = '\0'; + + ret = getaddrinfo (hostname, port_str, &req, &ainfo); + + if (ret != 0) + { + fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret)); + exit (1); + } + + ainfo_save = ainfo; + + do + { + if (ainfo->ai_family != AF_INET +#ifdef HAVE_IPV6 + && ainfo->ai_family != AF_INET6 +#endif /* HAVE_IPV6 */ + ) + continue; + + sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); + if (sock < 0) + continue; + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); + if (ret < 0) + { + close (sock); /* Avoid sd leak. */ + continue; + } + + ret = listen (sock, 3); + if (ret < 0) + { + close (sock); /* Avoid sd leak. */ + continue; + } + + vty_event (VTY_SERV, sock, NULL); + } + while ((ainfo = ainfo->ai_next) != NULL); + + freeaddrinfo (ainfo_save); +} +#endif /* HAVE_IPV6 && ! NRL */ + +/* Make vty server socket. */ +void +vty_serv_sock_family (unsigned short port, int family) +{ + int ret; + union sockunion su; + int accept_sock; + + memset (&su, 0, sizeof (union sockunion)); + su.sa.sa_family = family; + + /* Make new socket. */ + accept_sock = sockunion_stream_socket (&su); + if (accept_sock < 0) + return; + + /* This is server, so reuse address. */ + sockopt_reuseaddr (accept_sock); + sockopt_reuseport (accept_sock); + + /* Bind socket to universal address and given port. */ + ret = sockunion_bind (accept_sock, &su, port, NULL); + if (ret < 0) + { + close (accept_sock); /* Avoid sd leak. */ + return; + } + + /* Listen socket under queue 3. */ + ret = listen (accept_sock, 3); + if (ret < 0) + { + zlog (NULL, LOG_WARNING, "can't listen socket"); + close (accept_sock); /* Avoid sd leak. */ + return; + } + + /* Add vty server event. */ + vty_event (VTY_SERV, accept_sock, NULL); +} + +#ifdef VTYSH +/* For sockaddr_un. */ +#include <sys/un.h> + +/* VTY shell UNIX domain socket. */ +void +vty_serv_un (char *path) +{ + int ret; + int sock, len; + struct sockaddr_un serv; + mode_t old_mask; + + /* First of all, unlink existing socket */ + unlink (path); + + /* Set umask */ + old_mask = umask (0077); + + /* Make UNIX domain socket. */ + sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror ("sock"); + return; + } + + /* Make server socket. */ + memset (&serv, 0, sizeof (struct sockaddr_un)); + serv.sun_family = AF_UNIX; + strncpy (serv.sun_path, path, strlen (path)); +#ifdef HAVE_SUN_LEN + len = serv.sun_len = SUN_LEN(&serv); +#else + len = sizeof (serv.sun_family) + strlen (serv.sun_path); +#endif /* HAVE_SUN_LEN */ + + ret = bind (sock, (struct sockaddr *) &serv, len); + if (ret < 0) + { + perror ("bind"); + close (sock); /* Avoid sd leak. */ + return; + } + + ret = listen (sock, 5); + if (ret < 0) + { + perror ("listen"); + close (sock); /* Avoid sd leak. */ + return; + } + + umask (old_mask); + + vty_event (VTYSH_SERV, sock, NULL); +} + +/* #define VTYSH_DEBUG 1 */ + +static int +vtysh_accept (struct thread *thread) +{ + int accept_sock; + int sock; + int client_len; + struct sockaddr_un client; + struct vty *vty; + + accept_sock = THREAD_FD (thread); + + vty_event (VTYSH_SERV, accept_sock, NULL); + + memset (&client, 0, sizeof (struct sockaddr_un)); + client_len = sizeof (struct sockaddr_un); + + sock = accept (accept_sock, (struct sockaddr *) &client, &client_len); + + if (sock < 0) + { + zlog_warn ("can't accept vty socket : %s", strerror (errno)); + return -1; + } + +#ifdef VTYSH_DEBUG + printf ("VTY shell accept\n"); +#endif /* VTYSH_DEBUG */ + + vty = vty_new (); + vty->fd = sock; + vty->type = VTY_SHELL_SERV; + vty->node = VIEW_NODE; + + vty_event (VTYSH_READ, sock, vty); + + return 0; +} + +static int +vtysh_read (struct thread *thread) +{ + int ret; + int sock; + int nbytes; + struct vty *vty; + unsigned char buf[VTY_READ_BUFSIZ]; + u_char header[4] = {0, 0, 0, 0}; + + sock = THREAD_FD (thread); + vty = THREAD_ARG (thread); + vty->t_read = NULL; + + nbytes = read (sock, buf, VTY_READ_BUFSIZ); + if (nbytes <= 0) + { + vty_close (vty); +#ifdef VTYSH_DEBUG + printf ("close vtysh\n"); +#endif /* VTYSH_DEBUG */ + return 0; + } + +#ifdef VTYSH_DEBUG + printf ("line: %s\n", buf); +#endif /* VTYSH_DEBUG */ + + vty_ensure (vty, nbytes); + memcpy (vty->buf, buf, nbytes); + + /* Pass this line to parser. */ + ret = vty_execute (vty); + + vty_clear_buf (vty); + + /* Return result. */ +#ifdef VTYSH_DEBUG + printf ("result: %d\n", ret); + printf ("vtysh node: %d\n", vty->node); +#endif /* VTYSH_DEBUG */ + + header[3] = ret; + write (vty->fd, header, 4); + + vty_event (VTYSH_READ, sock, vty); + + return 0; +} +#endif /* VTYSH */ + +/* Determine address family to bind. */ +void +vty_serv_sock (const char *hostname, unsigned short port, char *path) +{ + /* If port is set to 0, do not listen on TCP/IP at all! */ + if (port) + { + +#ifdef HAVE_IPV6 +#ifdef NRL + vty_serv_sock_family (port, AF_INET); + vty_serv_sock_family (port, AF_INET6); +#else /* ! NRL */ + vty_serv_sock_addrinfo (hostname, port); +#endif /* NRL*/ +#else /* ! HAVE_IPV6 */ + vty_serv_sock_family (port, AF_INET); +#endif /* HAVE_IPV6 */ + } + +#ifdef VTYSH + vty_serv_un (path); +#endif /* VTYSH */ +} + +/* Close vty interface. */ +void +vty_close (struct vty *vty) +{ + int i; + + /* Cancel threads.*/ + if (vty->t_read) + thread_cancel (vty->t_read); + if (vty->t_write) + thread_cancel (vty->t_write); + if (vty->t_timeout) + thread_cancel (vty->t_timeout); + if (vty->t_output) + thread_cancel (vty->t_output); + + /* Flush buffer. */ + if (! buffer_empty (vty->obuf)) + buffer_flush_all (vty->obuf, vty->fd); + + /* Free input buffer. */ + buffer_free (vty->obuf); + + /* Free SB buffer. */ + if (vty->sb_buffer) + buffer_free (vty->sb_buffer); + + /* Free command history. */ + for (i = 0; i < VTY_MAXHIST; i++) + if (vty->hist[i]) + XFREE (MTYPE_VTY_HIST, vty->hist[i]); + + /* Unset vector. */ + vector_unset (vtyvec, vty->fd); + + /* Close socket. */ + if (vty->fd > 0) + close (vty->fd); + + if (vty->address) + XFREE (0, vty->address); + if (vty->buf) + XFREE (MTYPE_VTY, vty->buf); + + /* Check configure. */ + vty_config_unlock (vty); + + /* OK free vty. */ + XFREE (MTYPE_VTY, vty); +} + +/* When time out occur output message then close connection. */ +static int +vty_timeout (struct thread *thread) +{ + struct vty *vty; + + vty = THREAD_ARG (thread); + vty->t_timeout = NULL; + vty->v_timeout = 0; + + /* Clear buffer*/ + buffer_reset (vty->obuf); + vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE); + + /* Close connection. */ + vty->status = VTY_CLOSE; + vty_close (vty); + + return 0; +} + +/* Read up configuration file from file_name. */ +static void +vty_read_file (FILE *confp) +{ + int ret; + struct vty *vty; + + vty = vty_new (); + vty->fd = 0; /* stdout */ + vty->type = VTY_TERM; + vty->node = CONFIG_NODE; + + /* Execute configuration file */ + ret = config_from_file (vty, confp); + + if (ret != CMD_SUCCESS) + { + switch (ret) + { + case CMD_ERR_AMBIGUOUS: + fprintf (stderr, "Ambiguous command.\n"); + break; + case CMD_ERR_NO_MATCH: + fprintf (stderr, "There is no such command.\n"); + break; + } + fprintf (stderr, "Error occured during reading below line.\n%s\n", + vty->buf); + vty_close (vty); + exit (1); + } + + vty_close (vty); +} + +FILE * +vty_use_backup_config (char *fullpath) +{ + char *fullpath_sav, *fullpath_tmp; + FILE *ret = NULL; + struct stat buf; + int tmp, sav; + int c; + char buffer[512]; + + fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1); + strcpy (fullpath_sav, fullpath); + strcat (fullpath_sav, CONF_BACKUP_EXT); + if (stat (fullpath_sav, &buf) == -1) + { + free (fullpath_sav); + return NULL; + } + + fullpath_tmp = malloc (strlen (fullpath) + 8); + sprintf (fullpath_tmp, "%s.XXXXXX", fullpath); + + /* Open file to configuration write. */ + tmp = mkstemp (fullpath_tmp); + if (tmp < 0) + { + free (fullpath_sav); + free (fullpath_tmp); + return NULL; + } + + sav = open (fullpath_sav, O_RDONLY); + if (sav < 0) + { + free (fullpath_sav); + free (fullpath_tmp); + unlink (fullpath_tmp); + return NULL; + } + + while((c = read (sav, buffer, 512)) > 0) + write (tmp, buffer, c); + + close (sav); + close (tmp); + + if (link (fullpath_tmp, fullpath) == 0) + ret = fopen (fullpath, "r"); + + unlink (fullpath_tmp); + + free (fullpath_sav); + free (fullpath_tmp); + return fopen (fullpath, "r"); +} + +/* Read up configuration file from file_name. */ +void +vty_read_config (char *config_file, + char *config_current_dir, + char *config_default_dir) +{ + char *cwd; + FILE *confp = NULL; + char *fullpath; + + /* If -f flag specified. */ + if (config_file != NULL) + { + if (! IS_DIRECTORY_SEP (config_file[0])) + { + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_file) + 2); + sprintf (fullpath, "%s/%s", cwd, config_file); + } + else + fullpath = config_file; + + confp = fopen (fullpath, "r"); + + if (confp == NULL) + { + confp = vty_use_backup_config (fullpath); + if (confp) + fprintf (stderr, "WARNING: using backup configuration file!\n"); + else + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_file); + exit(1); + } + } + } + else + { + /* Relative path configuration file open. */ + if (config_current_dir) + { + confp = fopen (config_current_dir, "r"); + if (confp == NULL) + { + confp = vty_use_backup_config (config_current_dir); + if (confp) + fprintf (stderr, "WARNING: using backup configuration file!\n"); + } + } + + /* If there is no relative path exists, open system default file. */ + if (confp == NULL) + { +#ifdef VTYSH + int ret; + struct stat conf_stat; + + /* !!!!PLEASE LEAVE!!!! + This is NEEDED for use with vtysh -b, or else you can get + a real configuration food fight with a lot garbage in the + merged configuration file it creates coming from the per + daemon configuration files. This also allows the daemons + to start if there default configuration file is not + present or ignore them, as needed when using vtysh -b to + configure the daemons at boot - MAG */ + + /* Stat for vtysh Zebra.conf, if found startup and wait for + boot configuration */ + + if ( strstr(config_default_dir, "vtysh") == NULL) + { + ret = stat (integrate_default, &conf_stat); + if (ret >= 0) + { + return; + } + } +#endif /* VTYSH */ + + confp = fopen (config_default_dir, "r"); + if (confp == NULL) + { + confp = vty_use_backup_config (config_default_dir); + if (confp) + { + fprintf (stderr, "WARNING: using backup configuration file!\n"); + fullpath = config_default_dir; + } + else + { + fprintf (stderr, "can't open configuration file [%s]\n", + config_default_dir); + exit (1); + } + } + else + fullpath = config_default_dir; + } + else + { + /* Rleative path configuration file. */ + cwd = getcwd (NULL, MAXPATHLEN); + fullpath = XMALLOC (MTYPE_TMP, + strlen (cwd) + strlen (config_current_dir) + 2); + sprintf (fullpath, "%s/%s", cwd, config_current_dir); + } + } + vty_read_file (confp); + + fclose (confp); + + host_config_set (fullpath); +} + +/* Small utility function which output log to the VTY. */ +void +vty_log (const char *proto_str, const char *format, va_list va) +{ + int i; + struct vty *vty; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + if (vty->monitor) + vty_log_out (vty, proto_str, format, va); +} + +int +vty_config_lock (struct vty *vty) +{ + if (vty_config == 0) + { + vty->config = 1; + vty_config = 1; + } + return vty->config; +} + +int +vty_config_unlock (struct vty *vty) +{ + if (vty_config == 1 && vty->config == 1) + { + vty->config = 0; + vty_config = 0; + } + return vty->config; +} + +/* Master of the threads. */ +extern struct thread_master *master; +/* struct thread_master *master; */ + +static void +vty_event (enum event event, int sock, struct vty *vty) +{ + struct thread *vty_serv_thread; + + switch (event) + { + case VTY_SERV: + vty_serv_thread = thread_add_read (master, vty_accept, vty, sock); + vector_set_index (Vvty_serv_thread, sock, vty_serv_thread); + break; +#ifdef VTYSH + case VTYSH_SERV: + thread_add_read (master, vtysh_accept, vty, sock); + break; + case VTYSH_READ: + thread_add_read (master, vtysh_read, vty, sock); + break; +#endif /* VTYSH */ + case VTY_READ: + vty->t_read = thread_add_read (master, vty_read, vty, sock); + + /* Time out treatment. */ + if (vty->v_timeout) + { + if (vty->t_timeout) + thread_cancel (vty->t_timeout); + vty->t_timeout = + thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + } + break; + case VTY_WRITE: + if (! vty->t_write) + vty->t_write = thread_add_write (master, vty_flush, vty, sock); + break; + case VTY_TIMEOUT_RESET: + if (vty->t_timeout) + { + thread_cancel (vty->t_timeout); + vty->t_timeout = NULL; + } + if (vty->v_timeout) + { + vty->t_timeout = + thread_add_timer (master, vty_timeout, vty, vty->v_timeout); + } + break; + } +} + +DEFUN (config_who, + config_who_cmd, + "who", + "Display who is on vty\n") +{ + int i; + struct vty *v; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((v = vector_slot (vtyvec, i)) != NULL) + vty_out (vty, "%svty[%d] connected from %s.%s", + v->config ? "*" : " ", + i, v->address, VTY_NEWLINE); + return CMD_SUCCESS; +} + +/* Move to vty configuration mode. */ +DEFUN (line_vty, + line_vty_cmd, + "line vty", + "Configure a terminal line\n" + "Virtual terminal\n") +{ + vty->node = VTY_NODE; + return CMD_SUCCESS; +} + +/* Set time out value. */ +int +exec_timeout (struct vty *vty, char *min_str, char *sec_str) +{ + unsigned long timeout = 0; + + /* min_str and sec_str are already checked by parser. So it must be + all digit string. */ + if (min_str) + { + timeout = strtol (min_str, NULL, 10); + timeout *= 60; + } + if (sec_str) + timeout += strtol (sec_str, NULL, 10); + + vty_timeout_val = timeout; + vty->v_timeout = timeout; + vty_event (VTY_TIMEOUT_RESET, 0, vty); + + + return CMD_SUCCESS; +} + +DEFUN (exec_timeout_min, + exec_timeout_min_cmd, + "exec-timeout <0-35791>", + "Set timeout value\n" + "Timeout value in minutes\n") +{ + return exec_timeout (vty, argv[0], NULL); +} + +DEFUN (exec_timeout_sec, + exec_timeout_sec_cmd, + "exec-timeout <0-35791> <0-2147483>", + "Set the EXEC timeout\n" + "Timeout in minutes\n" + "Timeout in seconds\n") +{ + return exec_timeout (vty, argv[0], argv[1]); +} + +DEFUN (no_exec_timeout, + no_exec_timeout_cmd, + "no exec-timeout", + NO_STR + "Set the EXEC timeout\n") +{ + return exec_timeout (vty, NULL, NULL); +} + +/* Set vty access class. */ +DEFUN (vty_access_class, + vty_access_class_cmd, + "access-class WORD", + "Filter connections based on an IP access list\n" + "IP access list\n") +{ + if (vty_accesslist_name) + XFREE(MTYPE_VTY, vty_accesslist_name); + + vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]); + + return CMD_SUCCESS; +} + +/* Clear vty access class. */ +DEFUN (no_vty_access_class, + no_vty_access_class_cmd, + "no access-class [WORD]", + NO_STR + "Filter connections based on an IP access list\n" + "IP access list\n") +{ + if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0]))) + { + vty_out (vty, "Access-class is not currently applied to vty%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + XFREE(MTYPE_VTY, vty_accesslist_name); + + vty_accesslist_name = NULL; + + return CMD_SUCCESS; +} + +#ifdef HAVE_IPV6 +/* Set vty access class. */ +DEFUN (vty_ipv6_access_class, + vty_ipv6_access_class_cmd, + "ipv6 access-class WORD", + IPV6_STR + "Filter connections based on an IP access list\n" + "IPv6 access list\n") +{ + if (vty_ipv6_accesslist_name) + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + + vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]); + + return CMD_SUCCESS; +} + +/* Clear vty access class. */ +DEFUN (no_vty_ipv6_access_class, + no_vty_ipv6_access_class_cmd, + "no ipv6 access-class [WORD]", + NO_STR + IPV6_STR + "Filter connections based on an IP access list\n" + "IPv6 access list\n") +{ + if (! vty_ipv6_accesslist_name || + (argc && strcmp(vty_ipv6_accesslist_name, argv[0]))) + { + vty_out (vty, "IPv6 access-class is not currently applied to vty%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + + vty_ipv6_accesslist_name = NULL; + + return CMD_SUCCESS; +} +#endif /* HAVE_IPV6 */ + +/* vty login. */ +DEFUN (vty_login, + vty_login_cmd, + "login", + "Enable password checking\n") +{ + no_password_check = 0; + return CMD_SUCCESS; +} + +DEFUN (no_vty_login, + no_vty_login_cmd, + "no login", + NO_STR + "Enable password checking\n") +{ + no_password_check = 1; + return CMD_SUCCESS; +} + +DEFUN (service_advanced_vty, + service_advanced_vty_cmd, + "service advanced-vty", + "Set up miscellaneous service\n" + "Enable advanced mode vty interface\n") +{ + host.advanced = 1; + return CMD_SUCCESS; +} + +DEFUN (no_service_advanced_vty, + no_service_advanced_vty_cmd, + "no service advanced-vty", + NO_STR + "Set up miscellaneous service\n" + "Enable advanced mode vty interface\n") +{ + host.advanced = 0; + return CMD_SUCCESS; +} + +DEFUN (terminal_monitor, + terminal_monitor_cmd, + "terminal monitor", + "Set terminal line parameters\n" + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 1; + return CMD_SUCCESS; +} + +DEFUN (terminal_no_monitor, + terminal_no_monitor_cmd, + "terminal no monitor", + "Set terminal line parameters\n" + NO_STR + "Copy debug output to the current terminal line\n") +{ + vty->monitor = 0; + return CMD_SUCCESS; +} + +DEFUN (show_history, + show_history_cmd, + "show history", + SHOW_STR + "Display the session command history\n") +{ + int index; + + for (index = vty->hindex + 1; index != vty->hindex;) + { + if (index == VTY_MAXHIST) + { + index = 0; + continue; + } + + if (vty->hist[index] != NULL) + vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE); + + index++; + } + + return CMD_SUCCESS; +} + +/* Display current configuration. */ +int +vty_config_write (struct vty *vty) +{ + vty_out (vty, "line vty%s", VTY_NEWLINE); + + if (vty_accesslist_name) + vty_out (vty, " access-class %s%s", + vty_accesslist_name, VTY_NEWLINE); + + if (vty_ipv6_accesslist_name) + vty_out (vty, " ipv6 access-class %s%s", + vty_ipv6_accesslist_name, VTY_NEWLINE); + + /* exec-timeout */ + if (vty_timeout_val != VTY_TIMEOUT_DEFAULT) + vty_out (vty, " exec-timeout %ld %ld%s", + vty_timeout_val / 60, + vty_timeout_val % 60, VTY_NEWLINE); + + /* login */ + if (no_password_check) + vty_out (vty, " no login%s", VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +struct cmd_node vty_node = +{ + VTY_NODE, + "%s(config-line)# ", +}; + +/* Reset all VTY status. */ +void +vty_reset () +{ + int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + { + buffer_reset (vty->obuf); + vty->status = VTY_CLOSE; + vty_close (vty); + } + + for (i = 0; i < vector_max (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + + vty_timeout_val = VTY_TIMEOUT_DEFAULT; + + if (vty_accesslist_name) + { + XFREE(MTYPE_VTY, vty_accesslist_name); + vty_accesslist_name = NULL; + } + + if (vty_ipv6_accesslist_name) + { + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + vty_ipv6_accesslist_name = NULL; + } +} + +/* for ospf6d easy temprary reload function */ +/* vty_reset + close accept socket */ +void +vty_finish () +{ + int i; + struct vty *vty; + struct thread *vty_serv_thread; + + for (i = 0; i < vector_max (vtyvec); i++) + if ((vty = vector_slot (vtyvec, i)) != NULL) + { + buffer_reset (vty->obuf); + vty->status = VTY_CLOSE; + vty_close (vty); + } + + for (i = 0; i < vector_max (Vvty_serv_thread); i++) + if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL) + { + thread_cancel (vty_serv_thread); + vector_slot (Vvty_serv_thread, i) = NULL; + close (i); + } + + vty_timeout_val = VTY_TIMEOUT_DEFAULT; + + if (vty_accesslist_name) + { + XFREE(MTYPE_VTY, vty_accesslist_name); + vty_accesslist_name = NULL; + } + + if (vty_ipv6_accesslist_name) + { + XFREE(MTYPE_VTY, vty_ipv6_accesslist_name); + vty_ipv6_accesslist_name = NULL; + } +} + +void +vty_save_cwd () +{ + char *cwd; + + cwd = getcwd (NULL, MAXPATHLEN); + + vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1); + strcpy (vty_cwd, cwd); +} + +char * +vty_get_cwd () +{ + return vty_cwd; +} + +int +vty_shell (struct vty *vty) +{ + return vty->type == VTY_SHELL ? 1 : 0; +} + +int +vty_shell_serv (struct vty *vty) +{ + return vty->type == VTY_SHELL_SERV ? 1 : 0; +} + +void +vty_init_vtysh () +{ + vtyvec = vector_init (VECTOR_MIN_SIZE); +} + +/* Install vty's own commands like `who' command. */ +void +vty_init () +{ + /* For further configuration read, preserve current directory. */ + vty_save_cwd (); + + vtyvec = vector_init (VECTOR_MIN_SIZE); + + /* Initilize server thread vector. */ + Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE); + + /* Install bgp top node. */ + install_node (&vty_node, vty_config_write); + + install_element (VIEW_NODE, &config_who_cmd); + install_element (VIEW_NODE, &show_history_cmd); + install_element (ENABLE_NODE, &config_who_cmd); + install_element (CONFIG_NODE, &line_vty_cmd); + install_element (CONFIG_NODE, &service_advanced_vty_cmd); + install_element (CONFIG_NODE, &no_service_advanced_vty_cmd); + install_element (CONFIG_NODE, &show_history_cmd); + install_element (ENABLE_NODE, &terminal_monitor_cmd); + install_element (ENABLE_NODE, &terminal_no_monitor_cmd); + install_element (ENABLE_NODE, &show_history_cmd); + + install_default (VTY_NODE); + install_element (VTY_NODE, &exec_timeout_min_cmd); + install_element (VTY_NODE, &exec_timeout_sec_cmd); + install_element (VTY_NODE, &no_exec_timeout_cmd); + install_element (VTY_NODE, &vty_access_class_cmd); + install_element (VTY_NODE, &no_vty_access_class_cmd); + install_element (VTY_NODE, &vty_login_cmd); + install_element (VTY_NODE, &no_vty_login_cmd); +#ifdef HAVE_IPV6 + install_element (VTY_NODE, &vty_ipv6_access_class_cmd); + install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd); +#endif /* HAVE_IPV6 */ +} diff --git a/isisd/modified/zebra.h b/isisd/modified/zebra.h new file mode 100644 index 00000000..989e882d --- /dev/null +++ b/isisd/modified/zebra.h @@ -0,0 +1,313 @@ +/* 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__ +#endif /* SUNOS_5 */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#ifdef HAVE_STROPTS_H +#include <stropts.h> +#endif /* HAVE_STROPTS_H */ +#include <sys/fcntl.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif /* HAVE_SYS_SELECT_H */ +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/param.h> +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif /* HAVE_SYS_SYSCTL_H */ +#include <sys/ioctl.h> +#ifdef HAVE_SYS_CONF_H +#include <sys/conf.h> +#endif /* HAVE_SYS_CONF_H */ +#ifdef HAVE_SYS_KSYM_H +#include <sys/ksym.h> +#endif /* HAVE_SYS_KSYM_H */ +#include <syslog.h> +#include <time.h> +#include <sys/uio.h> +#include <sys/utsname.h> +#ifdef HAVE_RUSAGE +#include <sys/resource.h> +#endif /* HAVE_RUSAGE */ + +/* machine dependent includes */ +#ifdef SUNOS_5 +#include <limits.h> +#include <strings.h> +#endif /* SUNOS_5 */ + +/* machine dependent includes */ +#ifdef HAVE_LINUX_VERSION_H +#include <linux/version.h> +#endif /* HAVE_LINUX_VERSION_H */ + +#ifdef HAVE_ASM_TYPES_H +#include <asm/types.h> +#endif /* HAVE_ASM_TYPES_H */ + +/* misc include group */ +#include <stdarg.h> +#include <assert.h> + +/* network include group */ + +#include <sys/socket.h> + +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif /* HAVE_SYS_SOCKIO_H */ + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif /* HAVE_NETINET_IN_H */ +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#ifdef HAVE_NET_NETOPT_H +#include <net/netopt.h> +#endif /* HAVE_NET_NETOPT_H */ + +#include <net/if.h> + +#ifdef HAVE_NET_IF_DL_H +#include <net/if_dl.h> +#endif /* HAVE_NET_IF_DL_H */ + +#ifdef HAVE_NET_IF_VAR_H +#include <net/if_var.h> +#endif /* HAVE_NET_IF_VAR_H */ + +#include <net/route.h> + +#ifdef HAVE_NETLINK +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#else +#define RT_TABLE_MAIN 0 +#endif /* HAVE_NETLINK */ + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif /* HAVE_NETDB_H */ + +#include <arpa/inet.h> +#include <arpa/telnet.h> + +#ifdef HAVE_INET_ND_H +#include <inet/nd.h> +#endif /* HAVE_INET_ND_H */ + +#ifdef HAVE_NETINET_IN_VAR_H +#include <netinet/in_var.h> +#endif /* HAVE_NETINET_IN_VAR_H */ + +#ifdef HAVE_NETINET_IN6_VAR_H +#include <netinet/in6_var.h> +#endif /* HAVE_NETINET_IN6_VAR_H */ + +#ifdef HAVE_NETINET6_IN_H +#include <netinet6/in.h> +#endif /* HAVE_NETINET6_IN_H */ + + +#ifdef HAVE_NETINET6_IP6_H +#include <netinet6/ip6.h> +#endif /* HAVE_NETINET6_IP6_H */ + +#ifdef HAVE_NETINET_ICMP6_H +#include <netinet/icmp6.h> +#endif /* HAVE_NETINET_ICMP6_H */ + +#ifdef HAVE_NETINET6_ND6_H +#include <netinet6/nd6.h> +#endif /* HAVE_NETINET6_ND6_H */ + +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif /* HAVE_LIBUTIL_H */ + +#ifdef BSDI_NRL + +#ifdef HAVE_NETINET6_IN6_H +#include <netinet6/in6.h> +#endif /* HAVE_NETINET6_IN6_H */ + +#ifdef NRL +#include <netinet6/in6.h> +#endif /* NRL */ + +#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL + +/* BSD/OS 4.0 has lost belows defines, it should appear at + /usr/include/sys/socket.h. */ +#define CMSG_ALIGN(n) (((n) + 3) & ~3) +#define CMSG_SPACE(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l)) +#define CMSG_LEN(l) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l)) + +#endif /* BSDI_NRL */ + +/* The definition of struct in_pktinfo is missing in old version of + GLIBC 2.1 (Redhat 6.1). */ +#if defined (GNU_LINUX) && ! defined (HAVE_INPKTINFO) +struct in_pktinfo +{ + int ipi_ifindex; + struct in_addr ipi_spec_dst; + struct in_addr ipi_addr; +}; +#endif + +/* For old definition. */ +#ifndef IN6_ARE_ADDR_EQUAL +#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL +#endif /* IN6_ARE_ADDR_EQUAL */ + +/* Zebra message types. */ +#define ZEBRA_INTERFACE_ADD 1 +#define ZEBRA_INTERFACE_DELETE 2 +#define ZEBRA_INTERFACE_ADDRESS_ADD 3 +#define ZEBRA_INTERFACE_ADDRESS_DELETE 4 +#define ZEBRA_INTERFACE_UP 5 +#define ZEBRA_INTERFACE_DOWN 6 +#define ZEBRA_IPV4_ROUTE_ADD 7 +#define ZEBRA_IPV4_ROUTE_DELETE 8 +#define ZEBRA_IPV6_ROUTE_ADD 9 +#define ZEBRA_IPV6_ROUTE_DELETE 10 +#define ZEBRA_REDISTRIBUTE_ADD 11 +#define ZEBRA_REDISTRIBUTE_DELETE 12 +#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13 +#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14 +#define ZEBRA_IPV4_NEXTHOP_LOOKUP 15 +#define ZEBRA_IPV6_NEXTHOP_LOOKUP 16 +#define ZEBRA_IPV4_IMPORT_LOOKUP 17 +#define ZEBRA_IPV6_IMPORT_LOOKUP 18 +#define ZEBRA_MESSAGE_MAX 19 + +/* Zebra route's types. */ +#define ZEBRA_ROUTE_SYSTEM 0 +#define ZEBRA_ROUTE_KERNEL 1 +#define ZEBRA_ROUTE_CONNECT 2 +#define ZEBRA_ROUTE_STATIC 3 +#define ZEBRA_ROUTE_RIP 4 +#define ZEBRA_ROUTE_RIPNG 5 +#define ZEBRA_ROUTE_OSPF 6 +#define ZEBRA_ROUTE_OSPF6 7 +#define ZEBRA_ROUTE_ISIS 8 +#define ZEBRA_ROUTE_BGP 9 +#define ZEBRA_ROUTE_MAX 10 + +/* Zebra's family types. */ +#define ZEBRA_FAMILY_IPV4 1 +#define ZEBRA_FAMILY_IPV6 2 +#define ZEBRA_FAMILY_MAX 3 + +/* Error codes of zebra. */ +#define ZEBRA_ERR_RTEXIST -1 +#define ZEBRA_ERR_RTUNREACH -2 +#define ZEBRA_ERR_EPERM -3 +#define ZEBRA_ERR_RTNOEXIST -4 + +/* Zebra message flags */ +#define ZEBRA_FLAG_INTERNAL 0x01 +#define ZEBRA_FLAG_SELFROUTE 0x02 +#define ZEBRA_FLAG_BLACKHOLE 0x04 +#define ZEBRA_FLAG_IBGP 0x08 +#define ZEBRA_FLAG_SELECTED 0x10 +#define ZEBRA_FLAG_CHANGED 0x20 +#define ZEBRA_FLAG_STATIC 0x40 + +/* Zebra nexthop flags. */ +#define ZEBRA_NEXTHOP_IFINDEX 1 +#define ZEBRA_NEXTHOP_IFNAME 2 +#define ZEBRA_NEXTHOP_IPV4 3 +#define ZEBRA_NEXTHOP_IPV4_IFINDEX 4 +#define ZEBRA_NEXTHOP_IPV4_IFNAME 5 +#define ZEBRA_NEXTHOP_IPV6 6 +#define ZEBRA_NEXTHOP_IPV6_IFINDEX 7 +#define ZEBRA_NEXTHOP_IPV6_IFNAME 8 + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ +#endif + +/* Address family numbers from RFC1700. */ +#define AFI_IP 1 +#define AFI_IP6 2 +#define AFI_MAX 3 + +/* Subsequent Address Family Identifier. */ +#define SAFI_UNICAST 1 +#define SAFI_MULTICAST 2 +#define SAFI_UNICAST_MULTICAST 3 +#define SAFI_MPLS_VPN 4 +#define SAFI_MAX 5 + +/* Filter direction. */ +#define FILTER_IN 0 +#define FILTER_OUT 1 +#define FILTER_MAX 2 + +/* Default Administrative Distance of each protocol. */ +#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 +#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 +#define ZEBRA_STATIC_DISTANCE_DEFAULT 1 +#define ZEBRA_RIP_DISTANCE_DEFAULT 120 +#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120 +#define ZEBRA_OSPF_DISTANCE_DEFAULT 110 +#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110 +#define ZEBRA_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) = (V) | (F) +#define UNSET_FLAG(V,F) (V) = (V) & ~(F) + +/* AFI and SAFI type. */ +typedef u_int16_t afi_t; +typedef u_char safi_t; + +/* Zebra types. */ +typedef u_int16_t zebra_size_t; +typedef u_int8_t zebra_command_t; + +#endif /* _ZEBRA_H */ diff --git a/isisd/topology/Makefile.am b/isisd/topology/Makefile.am new file mode 100644 index 00000000..045c15c8 --- /dev/null +++ b/isisd/topology/Makefile.am @@ -0,0 +1,23 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" + +noinst_LIBRARIES = libtopology.a + +libtopology_a_SOURCES = \ + spgrid.c + +libtopology_a_DEPENDENCIES = @LIB_REGEX@ + +libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.a + +noinst_HEADERS = \ + spgrid.h + +EXTRA_DIST = regex.c regex-gnu.h + +depend: + @$(CPP) -MM $(INCLUDES) $(LDFLAGS) *.c + +## File dependency. diff --git a/isisd/topology/random.c b/isisd/topology/random.c new file mode 100644 index 00000000..d4ef9950 --- /dev/null +++ b/isisd/topology/random.c @@ -0,0 +1,154 @@ +/*********************************************************************/ +/* */ +/* current processor time in seconds */ +/* difference between two calls is processor time spent by your code */ +/* needs: <sys/types.h>, <sys/times.h> */ +/* depends on compiler and OS */ +/* */ +/*********************************************************************/ + +#include <sys/types.h> +#include <sys/times.h> + +float timer() + { struct tms hold; + + times(&hold); + return (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 ; +} + +/*********************************************************************/ +/* */ +/* 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 ) ; +} + + +/*********************************************************************/ + + +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 diff --git a/isisd/topology/spacyc.c b/isisd/topology/spacyc.c new file mode 100644 index 00000000..85314473 --- /dev/null +++ b/isisd/topology/spacyc.c @@ -0,0 +1,483 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <values.h> + +#include "random.c" + +#define DASH '-' +#define VERY_FAR 100000000 + + +/* generator of acyclic random networks for the shortest paths problem; + extended DIMACS format for output */ + +main ( argc, argv ) + +int argc; +char* argv[]; + +{ + +char args[30]; + +long n, + n0, + source, + i, + i0, + j, + dij; + +long m, + m0, + mc, + k; + +long *p, + p_t, + l, + lx; + +long seed, + seed1, + seed2; + +int ext=0; + +FILE *fout; + +/* variables for lengths generating */ +/* initialized by default values */ +int l_f = 0, ll_f = 0, lm_f = 0, ln_f = 0, ls_f = 0; +long ll = 10000, /* upper bound of the interval */ + lm = 0; /* lower bound of the interval */ +double ln = 0, /* l += ln * |i-j| */ + ls = 0; /* l += ls * |i-j|^2 */ + +/* variables for connecting path(s) */ +int c_f = 0, cl_f = 0, ch_f = 0, c_rand = 1; +long cl = 1; /* length of path arc */ +long ch; /* number of arcs in the path + n - by default */ + +/* 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, + pa_f = 0, pap_f = 0, pac_f = 0; +long pl, /* upper bound of the interval */ + pm; /* lower bound of the interval */ +double pn = 0, /* l += ln * |i-j| */ + ps = 0, /* l += ls * |i-j|^2 */ + pap = 0, /* part of nodes with alternative dustribution */ + pac = -1; /* multiplier for alternative distribution */ + +int np; /* number of parameter parsing now */ + +#define PRINT_ARC( i, j, length )\ +{\ +l = length;\ +if ( p_f ) l += ( p[i] - p[j] );\ +printf ("a %8ld %8ld %12ld\n", i, j, l );\ +} + + /* parsing parameters */ + +if ( argc < 2 ) goto usage; + +np = 0; + +strcpy ( args, argv[1] ); + + if ( ( args[0] == DASH ) && ( args[1] == 'h') + ) + goto help; + +if ( argc < 4 ) goto usage; + +/* first parameter - number of nodes */ +np = 1; +if ( ( n = atoi ( argv[1] ) ) < 2 ) goto usage; + +/* second parameter - number of arcs */ +np = 2; +if ( ( m = atoi ( argv[2] ) ) < n ) goto usage; + +/* third parameter - seed */ +np=3; +if ( ( seed = atoi ( argv[3] ) ) <= 0 ) goto usage; + +/* other parameters */ + +for ( np = 4; np < argc; np ++ ) + { + strcpy ( args, argv[np] ); + if ( args[0] != DASH ) goto usage; + + switch ( args[1] ) + { + + case 'l' : /* an interval for arc length */ + l_f = 1; + switch ( args[2] ) + { + case 'l': /* length of the interval */ + ll_f = 1; + ll = (long) atof ( &args[3] ); + break; + case 'm': /* minimal bound */ + lm_f = 1; + lm = (long ) atof ( &args[3] ); + break; + case 'n': /* additional length: l*|i-j| */ + ln_f = 1; + ln = atof ( &args[3] ); + break; + case 's': /* additional length: l*|i-j|^2 */ + ls_f = 1; + ls = atof ( &args[3] ); + break; + default: /* unknown switch value */ + goto usage; + } + break; + + case 'c' : /* connecting path(s) */ + c_f = 1; + switch ( args[2] ) + { + case 'l': /* length of path arc */ + c_rand = 0; /* fixed arc length */ + cl_f = 1; + cl = (long) atof ( &args[3] ); + break; + case 'h': /* number of arcs in connecting path */ + ch_f = 1; + ch = (long) atof ( &args[3] ); + if ( ch < 1 || ch > n ) goto usage; + break; + default: /* unknown switch value */ + goto usage; + } + 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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound of art. arc */ + sm_f = 1; + sm = (long) atof ( &args[3] ); + break; + default: /* unknown switch value */ + goto usage; + } + } + break; + + case 'p' : /* potentials */ + p_f = 1; + if ( strlen ( args ) > 2 ) + { + switch ( args[2] ) + { + case 'l': /* length of the interval */ + pl_f = 1; + pl = (long) atof ( &args[3] ); + break; + case 'm': /* minimal bound */ + pm_f = 1; + pm = (long ) atof ( &args[3] ); + break; + case 'n': /* additional length: l*|i-j| */ + pn_f = 1; + pn = atof ( &args[3] ); + break; + case 's': /* additional length: l*|i-j|^2 */ + ps_f = 1; + ps = atof ( &args[3] ); + break; + case 'a': /* bipolar distribution */ + pa_f = 1; + switch ( args[3] ) + { + case 'p': /* % of alternative potentials */ + pap_f = 1; + pap = atof ( &args[4] ); + if ( pap < 0 ) pap = 0; + if ( pap > 100 ) pap = 100; + pap /= 100; + break; + case 'c': /* multiplier */ + pac_f = 1; + pac = atof ( &args[4] ); + break; + default: /* unknown switch value */ + goto usage; + } + break; + default: /* unknown switch value */ + goto usage; + } + } + break; + + default : /* unknoun case */ + goto usage; + } + } + +/* ----- ajusting parameters ----- */ + +n0 = n; m0 = m; + +/* length parameters */ +if ( ll < lm ) { lx = ll; ll = lm; lm = lx; } + +/* potential parameters */ +if ( p_f ) + { + if ( ! pl_f ) pl = ll; + if ( ! pm_f ) pm = lm; + if ( pl < pm ) { lx = pl; pl = pm; pm = lx; } + } + +/* path(s) parameters */ +if ( ! ch_f ) ch = n - 1; +mc = n - 1; + + /* artifical source parameters */ +if ( s_f ) + { m0 += n; n0 ++ ; + if ( ! sm_f ) sm = sl; + if ( sl < sm ) { lx = sl; sl = sm; sm = lx; } + } + +/*----- printing title -----*/ + +printf ("c acyclic network for shortest paths problem\n"); +printf ("c extended DIMACS format\nc\n" ); + + +/* name of the problem */ +printf ("t ac_%ld_%ld_%ld_", n, m, seed ); +if ( l_f ) + printf ("%c", 'l'); +if ( c_f ) + printf ("%c", 'c'); +if ( s_f ) + printf ("%c", 's'); +if ( p_f ) + printf ("%c", 'p'); +printf ("\nc\n"); + +/* printing additional information */ +if ( l_f ) + printf ("c length -> min: %ld max: %ld k1: %.2f k2: %.2f\n", + lm, ll, ln, ls ); +if ( c_f ) + printf ("c path(s) -> number of arcs: %ld arc length: %ld\n", + ch, cl ); +if ( s_f ) + printf ("c length of arcs from artifical source -> min: %ld max: %ld\n", + sm, sl ); +if ( p_f ) + { + printf ("c potentials -> min: %ld max: %ld k1: %.2f k2: %.2f\n", + pm, pl, pn, ps ); + if ( pa_f ) + printf ("c potentials -> part of alternative distribution: %.2f k: %.2f\n", + pap, pac ); + } +printf ("c\n" ); + +printf ("p sp %8ld %8ld\nc\n", n0, m0 ); + +source = ( s_f ) ? n0 : 1; +printf ("n %8ld\nc\n", source ); + + +if ( p_f ) /* generating potentials */ + { + seed1 = 2*seed + 1; + p = (long*) calloc ( n+2, sizeof (long) ); + init_rand ( seed1); + pl = pl - pm + 1; + + for ( i = 0; i <= n; i ++ ) + { + p_t = pm + nrand ( pl ); + if ( pn_f ) p_t += (long) ( i * pn ); + if ( ps_f ) p_t += (long) ( i * ( i * ps )); + if ( pap_f ) + if ( rand01() < pap ) + p_t = (long) ( p_t * pac ); + p[i] = p_t; + } + p[n+1] = 0; + } + + +if ( s_f ) /* additional arcs from artifical source */ + { + seed2 = 3*seed + 1; + init_rand ( seed2 ); + sl = sl - sm + 1; + + for ( i = n; i > 1; i -- ) + { + s = sm + nrand ( sl ); + PRINT_ARC ( n0, i, s ) + } + + PRINT_ARC ( n0, 1, 0 ) + } + +/* initialize random number generator */ +init_rand ( seed ); +ll = ll - lm + 1; + +/* generating connecting path(s) */ +for ( i = 1; i < n; i ++ ) + { + if ( ( (i-1) % ch ) != 0 ) + i0 = i; + else + i0 = 1; + + if (c_rand) + cl = lm + nrand(ll); + PRINT_ARC ( i0, i+1, cl ) + } + +/* generating random arcs */ + + +for ( k = 1; k <= m - mc; k ++ ) + { + i = 1 + nrand ( n ); + + do + j = 1 + nrand ( n ); + while ( j == i ); + + if ( i > j ) + { i0 = i; i = j; j = i0; } + + dij = j - i; + l = lm + nrand ( ll ); + if ( ln_f ) l += (long) ( dij * ln ); + if ( ls_f ) l += (long) ( dij * ( dij * ls ) ); + PRINT_ARC ( i, j, l ); + } + +/* all is done */ +exit (ext); + +/* ----- wrong usage ----- */ + + usage: +fprintf ( stderr, +"\nusage: %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\ +help: %s -h\n\n", argv[0], argv[0] ); + +if ( np > 0 ) + fprintf ( stderr, "error in parameter # %d\n\n", np ); +exit (4); + +/* ---- help ---- */ + + help: + +if ( args[2] == 'h') goto hhelp; + +fprintf ( stderr, +"\n'%s' - acyclic network generator for shortest paths problem.\n\ +Generates problems in extended DIMACS format.\n\ +\n\ + %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\ + %s -hh\n\ +\n\ + #i - integer number #f - real number\n\ +\n\ +-ll#i - #i is the upper bound on arc lengths (default 10000)\n\ +-lm#i - #i is the lower bound on arc lengths (default 0)\n\ +-cl#i - #i is length of arcs in connecting path(s) (default random)\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\ +\n\ +-hh - extended help \n\n", +argv[0], argv[0], argv[0] ); + +exit (0); + +/* --------- sophisticated help ------------ */ + hhelp: + +if ( argc < 3 ) + fout = stderr; +else + fout = fopen ( argv[2], "w" ); + +if ( fout == NULL ) +{ fprintf ( stderr, "\nCan't open file '%s' for writing help\n\n", argv[2] ); + exit ( 2 ); +} + +fprintf (fout, +"\n'%s' - acyclic network generator for shortest paths problem.\n\ +Generates problems in extended DIMACS format.\n\ +\n\ + %s n m seed [ -ll#i -lm#i -ln#f -ls#f\n\ + -p -pl#i -pm#i -pn#f -ps#f -pap#i -pac#f\n\ + -cl#i -ch#i\n\ + -s -sl#i -sm#i\n\ + ]\n\ + %s -hh file_name\n\ +\n\ + #i - integer number #f - real number\n\ +\n\ + Arc length parameters:\n\ +-ll#i - #i is the upper bound on arc lengths (default 10000)\n\ +-lm#i - #i is the lower bound on arc lengths (default 0)\n\ +-ln#f - multipliy l(i, j) by #f * |i-j| (default 0)\n\ +-ls#f - multipliy l(i, j) by #f * |i-j|^2 (default 0)\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 * i (default 0)\n\ +-ps#f - multiply p(i) by #f * i^2 (default 0)\n\ +-pap#i - percentage of alternative potential nodes (default 0)\n\ +-pac#f - if i is alternative, multiply p(i) by #f (default -1)\n\ +\n\ + Connecting path(s) parameters:\n\ +-cl#i - #i is length of arcs in connecting path(s) (default random)\n\ +-ch#i - #i is length of connecting path(s) (default n-1)\n\ +\n\ + 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\ +\n\ +-hh file_name - save this help in the file 'file_name'\n\n", +argv[0], argv[0], argv[0] ); + +exit (0); +} + + + diff --git a/isisd/topology/spgrid.c b/isisd/topology/spgrid.c new file mode 100644 index 00000000..22d3a804 --- /dev/null +++ b/isisd/topology/spgrid.c @@ -0,0 +1,729 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <values.h> + +#include "random.c" + +#include <zebra.h> + +#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) + +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, 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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound */ + cm_f = 1; + cm = (long ) atof ( &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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound */ + am_f = 1; + am = (long ) atof ( &args[3] ); + break; + case 'x': /* number of additional arcs */ + ax_f = 1; + ax = (long ) atof ( &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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound */ + im_f = 1; + im = (long ) atof ( &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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound of art. arc */ + sm_f = 1; + sm = (long) atof ( &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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound */ + pm_f = 1; + pm = (long ) atof ( &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)MAXLONG || m >= (double)MAXLONG ) + { + 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; +} + + + diff --git a/isisd/topology/spgrid.h b/isisd/topology/spgrid.h new file mode 100644 index 00000000..f96c00f3 --- /dev/null +++ b/isisd/topology/spgrid.h @@ -0,0 +1,45 @@ +/* + * 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, char **argv); + + +#endif /* _ZEBRA_ISIS_TOPOLOGY_SPGRID_H */ + + + + + + diff --git a/isisd/topology/sprand.c b/isisd/topology/sprand.c new file mode 100644 index 00000000..28b58b30 --- /dev/null +++ b/isisd/topology/sprand.c @@ -0,0 +1,499 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <values.h> + +#include "random.c" + +#define DASH '-' +#define VERY_FAR 100000000 + +/* generator of random networks for the shortest paths problem; + extended DIMACS format for output */ + +main ( argc, argv ) + +int argc; +char* argv[]; + +{ + +char args[30]; + +long n, + n0, + source, + i, + i0, + j, + dij; + +long m, + m0, + mc, + k; + +long *p, + p_t, + l, + lx; + +long seed, + seed1, + seed2; + +int ext=0; + +FILE *fout; + +/* variables for lengths generating */ +/* initialized by default values */ +int l_f = 0, ll_f = 0, lm_f = 0, ln_f = 0, ls_f = 0; +long ll = 10000, /* length of the interval */ + lm = 0; /* minimal bound of the interval */ +double ln = 0, /* l += ln * |i-j| */ + ls = 0; /* l += ls * |i-j|^2 */ + +/* variables for connecting cycle(s) */ +int c_f = 0, cl_f = 0, ch_f = 0, c_random = 1; +long cl = 1; /* length of cycle arc */ +long ch; /* number of arcs in the cycle + n - by default */ + +/* 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, + pa_f = 0, pap_f = 0, pac_f = 0; +long pl, /* length of the interval */ + pm; /* minimal bound of the interval */ +double pn = 0, /* l += ln * |i-j| */ + ps = 0, /* l += ls * |i-j|^2 */ + pap = 0, /* part of nodes with alternative dustribution */ + pac = -1; /* multiplier for alternative distribution */ + +int np; /* number of parameter parsing now */ + +#define PRINT_ARC( i, j, length )\ +{\ +l = length;\ +if ( p_f ) l += ( p[i] - p[j] );\ +printf ("a %8ld %8ld %12ld\n", i, j, l );\ +} + + /* parsing parameters */ + +if ( argc < 2 ) goto usage; + +np = 0; + +strcpy ( args, argv[1] ); + + if ( ( args[0] == DASH ) && ( args[1] == 'h') + ) + goto help; + +if ( argc < 4 ) goto usage; + +/* first parameter - number of nodes */ +np = 1; +if ( ( n = atoi ( argv[1] ) ) < 2 ) goto usage; + +/* second parameter - number of arcs */ +np = 2; +if ( ( m = atoi ( argv[2] ) ) < n ) goto usage; + +/* third parameter - seed */ +np=3; +if ( ( seed = atoi ( argv[3] ) ) <= 0 ) goto usage; + +/* other parameters */ + +for ( np = 4; np < argc; np ++ ) + { + strcpy ( args, argv[np] ); + if ( args[0] != DASH ) goto usage; + + switch ( args[1] ) + { + + case 'l' : /* an interval for arc length */ + l_f = 1; + switch ( args[2] ) + { + case 'l': /* length of the interval */ + ll_f = 1; + ll = (long) atof ( &args[3] ); + break; + case 'm': /* minimal bound */ + lm_f = 1; + lm = (long ) atof ( &args[3] ); + break; + case 'n': /* additional length: l*|i-j| */ + ln_f = 1; + ln = atof ( &args[3] ); + break; + case 's': /* additional length: l*|i-j|^2 */ + ls_f = 1; + ls = atof ( &args[3] ); + break; + default: /* unknown switch value */ + goto usage; + } + break; + + case 'c' : /* connecting cycle(s) */ + c_f = 1; + switch ( args[2] ) + { + case 'l': + c_random = 0; + cl_f = 1; + cl = (long) atof ( &args[3] ); + if ( cl < 0 ) goto usage; + break; + case 'h': + ch_f = 1; + ch = (long) atof ( &args[3] ); + if ( ch < 2 || ch > n ) goto usage; + break; + default: /* unknown switch value */ + goto usage; + } + 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 = (long) atof ( &args[3] ); + break; + case 'm': /* lower bound of art. arc */ + sm_f = 1; + sm = (long) atof ( &args[3] ); + break; + default: /* unknown switch value */ + goto usage; + } + } + break; + + case 'p' : /* potentials */ + p_f = 1; + if ( strlen ( args ) > 2 ) + { + switch ( args[2] ) + { + case 'l': /* length of the interval */ + pl_f = 1; + pl = (long) atof ( &args[3] ); + break; + case 'm': /* minimal bound */ + pm_f = 1; + pm = (long ) atof ( &args[3] ); + break; + case 'n': /* additional length: l*|i-j| */ + pn_f = 1; + pn = atof ( &args[3] ); + break; + case 's': /* additional length: l*|i-j|^2 */ + ps_f = 1; + ps = atof ( &args[3] ); + break; + case 'a': /* bipolar distribution */ + pa_f = 1; + switch ( args[3] ) + { + case 'p': /* % of alternative potentials */ + pap_f = 1; + pap = atof ( &args[4] ); + if ( pap < 0 ) pap = 0; + if ( pap > 100 ) pap = 100; + pap /= 100; + break; + case 'c': /* multiplier */ + pac_f = 1; + pac = atof ( &args[4] ); + break; + default: /* unknown switch value */ + goto usage; + } + break; + default: /* unknown switch value */ + goto usage; + } + } + break; + + default : /* unknoun case */ + goto usage; + } + } + + +/* ----- ajusting parameters ----- */ + +n0 = n; m0 = m; + +/* length parameters */ +if ( ll < lm ) { lx = ll; ll = lm; lm = lx; } + +/* potential parameters */ +if ( p_f ) + { + if ( ! pl_f ) pl = ll; + if ( ! pm_f ) pm = lm; + if ( pl < pm ) { lx = pl; pl = pm; pm = lx; } + } + +/* path(s) parameters */ +if ( ! ch_f ) ch = n; + +mc = n + (n-2) / (ch-1); +if ( mc > m ) + { fprintf ( stderr, + "Error: not enough arcs for generating connecting cycle(s)\n" ); + exit (4); + } + + /* artifical source parameters */ +if ( s_f ) + { m0 += n; n0 ++ ; + if ( ! sm_f ) sm = sl; + if ( sl < sm ) { lx = sl; sl = sm; sm = lx; } + } + +/* printing title */ +printf ("c random network for shortest paths problem\n"); +printf ("c extended DIMACS format\nc\n" ); + +/* name of the problem */ +printf ("t rd_%ld_%ld_%ld_", n, m, seed ); +if ( l_f ) + printf ("%c", 'l'); +if ( c_f ) + printf ("%c", 'c'); +if ( s_f ) + printf ("%c", 's'); +if ( p_f ) + printf ("%c", 'p'); +printf ("\nc\n"); + +/* printing additional information */ +if ( l_f ) + printf ("c length -> min: %ld max: %ld k1: %.2f k2: %.2f\n", + lm, ll, ln, ls ); +if ( c_f ) + { + if ( c_random ) + printf ("c cycle -> number of arcs: %ld arc length: random\n", ch); + else + printf ("c cycle -> number of arcs: %ld arc length: %ld\n", + ch, cl ); + } +if ( s_f ) + printf ("c length of arcs from artifical source -> min: %ld max: %ld\n", + sm, sl ); +if ( p_f ) + { + printf ("c potentials -> min: %ld max: %ld k1: %.2f k2: %.2f\n", + pm, pl, pn, ps ); + if ( pa_f ) + printf ("c potentials -> part of alternative distribution: %.2f k: %.2f\n", + pap, pac ); + } +printf ("c\n" ); + + +printf ("p sp %8ld %8ld\nc\n", n0, m0 ); + +source = ( s_f ) ? n0 : 1; +printf ("n %8ld\nc\n", source ); + +if ( p_f ) /* generating potentials */ + { + p = (long*) calloc ( n+2, sizeof (long) ); + seed1 = 2*seed + 1; + init_rand ( seed1); + pl = pl - pm + 1; + + for ( i = 0; i <= n; i ++ ) + { + p_t = pm + nrand ( pl ); + if ( pn_f ) p_t += (long) ( i * pn ); + if ( ps_f ) p_t += (long) ( i * ( i * ps )); + if ( pap_f ) + if ( rand01() < pap ) + p_t = (long) ( p_t * pac ); + p[i] = p_t; + } + p[n+1] = 0; + } + + +if ( s_f ) /* additional arcs from artifical source */ + { + seed2 = 3*seed + 1; + init_rand ( seed2 ); + sl = sl - sm + 1; + + for ( i = n; i > 1; i -- ) + { + s = sm + nrand ( sl ); + PRINT_ARC ( n0, i, s ) + } + + PRINT_ARC ( n0, 1, 0 ) + } + +/* initialize random number generator */ +init_rand ( seed ); +ll = ll - lm + 1; + +/* generating connecting cycle(s) */ +if (c_random) + cl = lm + nrand ( ll ); +PRINT_ARC ( 1, 2, cl ) +if (c_random) + cl = lm + nrand ( ll ); +PRINT_ARC ( n, 1, cl ) + +for ( i = 2; i < n; i ++ ) + { + if (c_random) + cl = lm + nrand ( ll ); + + if ( ( (i-1) % (ch-1) ) != 0 ) + PRINT_ARC ( i, i+1, cl ) + else + { PRINT_ARC ( i, 1, cl ) + if (c_random) + cl = lm + nrand ( ll ); + PRINT_ARC ( 1, i+1, cl ) + } + } + +/* generating random arcs */ + +for ( k = 1; k <= m - mc; k ++ ) + { + i = 1 + nrand ( n ); + + do + j = 1 + nrand ( n ); + while ( j == i ); + + dij = ( i > j ) ? ( i - j ) : ( j - i ); + l = lm + nrand ( ll ); + if ( ln_f ) l += (long) ( dij * ln ); + if ( ls_f ) l += (long) ( dij * ( dij * ls ) ); + PRINT_ARC ( i, j, l ); + } + +/* all is done */ +exit (ext); + +/* ----- wrong usage ----- */ + + usage: +fprintf ( stderr, +"\nusage: %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\ +help: %s -h\n\n", argv[0], argv[0] ); + +if ( np > 0 ) + fprintf ( stderr, "error in parameter # %d\n\n", np ); +exit (4); + +/* ---- help ---- */ + + help: + +if ( args[2] == 'h') goto hhelp; + +fprintf ( stderr, +"\n'%s' - random network generator for shortest paths problem.\n\ +Generates problems in extended DIMACS format.\n\ +\n\ + %s n m seed [ -ll#i -lm#i -cl#i -p -pl#i -pm#i ... ]\n\ + %s -hh\n\ +\n\ + #i - integer number #f - real number\n\ +\n\ +-ll#i - #i is the upper bound on arc lengths (default 10000)\n\ +-lm#i - #i is the lower bound on arc lengths (default 0)\n\ +-cl#i - #i is length of arcs in connecting cycle(s) (default random)\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\ +\n\ +-hh - extended help \n\n", +argv[0], argv[0], argv[0] ); + +exit (0); + +/* --------- sophisticated help ------------ */ + hhelp: + +if ( argc < 3 ) + fout = stderr; +else + fout = fopen ( argv[2], "w" ); + +if ( fout == NULL ) +{ fprintf ( stderr, "\nCan't open file '%s' for writing help\n\n", argv[2] ); + exit ( 2 ); +} + +fprintf (fout, +"\n'%s' - random network generator for shortest paths problem.\n\ +Generates problems in extended DIMACS format.\n\ +\n\ + %s n m seed [ -ll#i -lm#i -ln#f -ls#f\n\ + -p -pl#i -pm#i -pn#f -ps#f -pap#i -pac#f\n\ + -cl#i -ch#i\n\ + -s -sl#i -sm#i\n\ + ]\n\ + %s -hh file_name\n\ +\n\ + #i - integer number #f - real number\n\ +\n\ + Arc length parameters:\n\ +-ll#i - #i is the upper bound on arc lengths (default 10000)\n\ +-lm#i - #i is the lower bound on arc lengths (default 0)\n\ +-ln#f - multipliy l(i, j) by #f * |i-j| (default 0)\n\ +-ls#f - multipliy l(i, j) by #f * |i-j|^2 (default 0)\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 * i (default 0)\n\ +-ps#f - multiply p(i) by #f * i^2 (default 0)\n\ +-pap#i - percentage of alternative potential nodes (default 0)\n\ +-pac#f - if i is alternative, multiply p(i) by #f (default -1)\n\ +\n\ + Connecting cycle(s) parameters:\n\ +-cl#i - #i is length of arcs in connecting cycle(s) (default random)\n\ +-ch#i - #i is length of connecting cycles (default n)\n\ +\n\ + 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\ +\n\ +-hh file_name - save this help in the file 'file_name'\n\n", +argv[0], argv[0], argv[0] ); + +exit (0); +} + + + |